diff --git a/doc/Settings.md b/doc/Settings.md index fcd14080b0..628cabcb52 100644 --- a/doc/Settings.md +++ b/doc/Settings.md @@ -312,3 +312,14 @@ You can enable the feature as shown below. "configuration03": true }, ``` + +### proxy + +This feature enables the use of web proxies. +You can enable the feature as shown below. + +```json + "experimentalFeatures": { + "proxy": true + }, +``` diff --git a/doc/admx/DesktopAppInstaller.admx b/doc/admx/DesktopAppInstaller.admx index 64b911e1f2..9cad850345 100644 --- a/doc/admx/DesktopAppInstaller.admx +++ b/doc/admx/DesktopAppInstaller.admx @@ -166,5 +166,22 @@ + + + + + + + + + + + + + + + + + diff --git a/doc/admx/en-US/DesktopAppInstaller.adml b/doc/admx/en-US/DesktopAppInstaller.adml index 4e80a38093..5c3142ab6b 100644 --- a/doc/admx/en-US/DesktopAppInstaller.adml +++ b/doc/admx/en-US/DesktopAppInstaller.adml @@ -100,7 +100,7 @@ If you disable or do not configure this setting, users will not be able to insta If you disable this policy, users will not be able execute the Windows Package Manager CLI, and PowerShell cmdlets. - If you enable, or do not configuring this policy, users will be able to execute the Windows Package Manager CLI commands, and PowerShell cmdlets. (Provided “Enable App Installer” policy is not disabled). + If you enable, or do not configure this policy, users will be able to execute the Windows Package Manager CLI commands, and PowerShell cmdlets. (Provided “Enable App Installer” policy is not disabled). This policy does not override the “Enable App Installer” policy. Enable Windows Package Manager Configuration @@ -109,6 +109,19 @@ If you disable or do not configure this setting, users will not be able to insta If you enable or do not configure this setting, users will be able to use the Windows Package Manager configuration feature. If you disable this setting, users will not be able to use the Windows Package Manager configuration feature. + Enable Windows Package Manager Proxy command line options + + This policy controls whether the Windows Package Manager usage of proxy can be configured by users through the command line. + + If you enable this setting, users will be able to configure the Windows Package Manager's use of proxy through the command line. + + If you disable or do not configure this setting, users will not be able to to configure the Windows Package Manager's use of proxy through the command line. + Set Windows Package Manager Default Proxy + This policy controls the default proxy used by the Windows Package Manager. + +If you disable or do not configure this setting, no proxy will be used by default. + +If you enable this setting, the specified proxy will be used by default. @@ -120,6 +133,11 @@ If you disable this setting, users will not be able to use the Windows Package M Allowed Sources: + + + + + diff --git a/schemas/JSON/settings/settings.export.schema.0.1.json b/schemas/JSON/settings/settings.export.schema.0.1.json index 17d0e8d5e4..f8809255f5 100644 --- a/schemas/JSON/settings/settings.export.schema.0.1.json +++ b/schemas/JSON/settings/settings.export.schema.0.1.json @@ -16,8 +16,26 @@ "description": "Enable installing local manifests.", "type": "boolean", "default": false + }, + "InstallerHashOverride": { + "description": "Enable overriding installer hash validation.", + "type": "boolean", + "default": false + }, + "LocalArchiveMalwareScanOverride": { + "description": "Enable overriding malware scan for local archives.", + "type": "boolean", + "default": false + }, + "ProxyCommandLineOptions": { + "description": "Enable using command line options for proxy.", + "type": "boolean", + "default": false + }, + "DefaultProxy": { + "description": "Default proxy.", + "type": "string" } - } }, "UserSettingsFile": { "description": "Path for the winget's user settings file.", diff --git a/schemas/JSON/settings/settings.schema.0.2.json b/schemas/JSON/settings/settings.schema.0.2.json index 3a35440415..80e224487b 100644 --- a/schemas/JSON/settings/settings.schema.0.2.json +++ b/schemas/JSON/settings/settings.schema.0.2.json @@ -266,8 +266,13 @@ "type": "boolean", "default": false }, - "configuration": { - "description": "Enable support for configuration", + "configuration03": { + "description": "Enable support for configuration schema 0.3", + "type": "boolean", + "default": false + }, + "proxy": { + "description": "Enable support for proxies", "type": "boolean", "default": false } diff --git a/src/AppInstallerCLICore/Argument.cpp b/src/AppInstallerCLICore/Argument.cpp index 7497468840..6299beb909 100644 --- a/src/AppInstallerCLICore/Argument.cpp +++ b/src/AppInstallerCLICore/Argument.cpp @@ -151,6 +151,10 @@ namespace AppInstaller::CLI return { type, "enable"_liv, ArgTypeCategory::None, ArgTypeExclusiveSet::EnableDisable }; case Execution::Args::Type::AdminSettingDisable: return { type, "disable"_liv, ArgTypeCategory::None, ArgTypeExclusiveSet::EnableDisable }; + case Execution::Args::Type::SettingName: + return { type, "setting"_liv }; + case Execution::Args::Type::SettingValue: + return { type, "value"_liv }; // Upgrade command case Execution::Args::Type::All: @@ -233,6 +237,11 @@ namespace AppInstaller::CLI case Execution::Args::Type::AcceptSourceAgreements: return { type, "accept-source-agreements"_liv, ArgTypeCategory::ExtendedSource }; + case Execution::Args::Type::Proxy: + return { type, "proxy"_liv, ArgTypeCategory::CopyValueToSubContext, ArgTypeExclusiveSet::Proxy }; + case Execution::Args::Type::NoProxy: + return { type, "no-proxy"_liv, ArgTypeCategory::CopyFlagToSubContext, ArgTypeExclusiveSet::Proxy }; + case Execution::Args::Type::ToolVersion: return { type, "version"_liv, 'v' }; @@ -268,7 +277,7 @@ namespace AppInstaller::CLI case Args::Type::MultiQuery: return Argument{ type, Resource::String::MultiQueryArgumentDescription, ArgumentType::Positional }.SetCountLimit(128); case Args::Type::Manifest: - return Argument{ type, Resource::String::ManifestArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help, Settings::TogglePolicy::Policy::LocalManifestFiles, Settings::AdminSetting::LocalManifestFiles }; + return Argument{ type, Resource::String::ManifestArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help, Settings::TogglePolicy::Policy::LocalManifestFiles, Settings::BoolAdminSetting::LocalManifestFiles }; case Args::Type::Id: return Argument{ type, Resource::String::IdArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help }; case Args::Type::Name: @@ -308,7 +317,7 @@ namespace AppInstaller::CLI case Args::Type::InstallLocation: return Argument{ type, Resource::String::LocationArgumentDescription, ArgumentType::Standard }; case Args::Type::HashOverride: - return Argument{ type, Resource::String::HashOverrideArgumentDescription, ArgumentType::Flag, Settings::TogglePolicy::Policy::HashOverride, Settings::AdminSetting::InstallerHashOverride }; + return Argument{ type, Resource::String::HashOverrideArgumentDescription, ArgumentType::Flag, Settings::TogglePolicy::Policy::HashOverride, Settings::BoolAdminSetting::InstallerHashOverride }; case Args::Type::AcceptPackageAgreements: return Argument{ type, Resource::String::AcceptPackageAgreementsArgumentDescription, ArgumentType::Flag }; case Args::Type::NoUpgrade: @@ -324,7 +333,7 @@ namespace AppInstaller::CLI case Args::Type::SkipDependencies: return Argument{ type, Resource::String::SkipDependenciesArgumentDescription, ArgumentType::Flag, false }; case Args::Type::IgnoreLocalArchiveMalwareScan: - return Argument{ type, Resource::String::IgnoreLocalArchiveMalwareScanArgumentDescription, ArgumentType::Flag, Settings::TogglePolicy::Policy::LocalArchiveMalwareScanOverride, Settings::AdminSetting::LocalArchiveMalwareScanOverride }; + return Argument{ type, Resource::String::IgnoreLocalArchiveMalwareScanArgumentDescription, ArgumentType::Flag, Settings::TogglePolicy::Policy::LocalArchiveMalwareScanOverride, Settings::BoolAdminSetting::LocalArchiveMalwareScanOverride }; case Args::Type::SourceName: return Argument{ type, Resource::String::SourceNameArgumentDescription, ArgumentType::Positional, false }; case Args::Type::SourceArg: @@ -379,6 +388,10 @@ namespace AppInstaller::CLI return Argument{ type, Resource::String::AllowRebootArgumentDescription, ArgumentType::Flag }; case Args::Type::IgnoreResumeLimit: return Argument{ type, Resource::String::IgnoreResumeLimitArgumentDescription, ArgumentType::Flag, ExperimentalFeature::Feature::Resume }; + case Args::Type::Proxy: + return Argument{ type, Resource::String::ProxyArgumentDescription, ArgumentType::Standard, ExperimentalFeature::Feature::Proxy, TogglePolicy::Policy::ProxyCommandLineOptions, BoolAdminSetting::ProxyCommandLineOptions }; + case Args::Type::NoProxy: + return Argument{ type, Resource::String::NoProxyArgumentDescription, ArgumentType::Flag, ExperimentalFeature::Feature::Proxy, TogglePolicy::Policy::ProxyCommandLineOptions, BoolAdminSetting::ProxyCommandLineOptions }; default: THROW_HR(E_UNEXPECTED); } @@ -394,6 +407,8 @@ namespace AppInstaller::CLI args.push_back(ForType(Args::Type::RetroStyle)); args.push_back(ForType(Args::Type::VerboseLogs)); args.emplace_back(Args::Type::DisableInteractivity, Resource::String::DisableInteractivityArgumentDescription, ArgumentType::Flag, false); + args.push_back(ForType(Args::Type::Proxy)); + args.push_back(ForType(Args::Type::NoProxy)); } std::string Argument::GetUsageString() const diff --git a/src/AppInstallerCLICore/Argument.h b/src/AppInstallerCLICore/Argument.h index d33741eaf1..741c2de068 100644 --- a/src/AppInstallerCLICore/Argument.h +++ b/src/AppInstallerCLICore/Argument.h @@ -85,6 +85,7 @@ namespace AppInstaller::CLI PurgePreserve = 0x4, PinType = 0x8, StubType = 0x10, + Proxy = 0x20, // This must always be at the end Max @@ -211,7 +212,7 @@ namespace AppInstaller::CLI Argument::Visibility GetVisibility() const; Settings::ExperimentalFeature::Feature Feature() const { return m_feature; } Settings::TogglePolicy::Policy GroupPolicy() const { return m_groupPolicy; } - Settings::AdminSetting AdminSetting() const { return m_adminSetting; } + Settings::BoolAdminSetting AdminSetting() const { return m_adminSetting; } Argument& SetRequired(bool required) { m_required = required; return *this; } Argument& SetCountLimit(size_t countLimit) { m_countLimit = countLimit; return *this; } @@ -237,12 +238,15 @@ namespace AppInstaller::CLI Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Argument::Visibility visibility, bool required, Settings::ExperimentalFeature::Feature feature) : m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type), m_visibility(visibility), m_required(required), m_feature(feature) {} - Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Settings::TogglePolicy::Policy groupPolicy, Settings::AdminSetting adminSetting) : + Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Settings::TogglePolicy::Policy groupPolicy, Settings::BoolAdminSetting adminSetting) : m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type), m_groupPolicy(groupPolicy), m_adminSetting(adminSetting) {} - Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Argument::Visibility visibility, Settings::TogglePolicy::Policy groupPolicy, Settings::AdminSetting adminSetting) : + Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Argument::Visibility visibility, Settings::TogglePolicy::Policy groupPolicy, Settings::BoolAdminSetting adminSetting) : m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type), m_visibility(visibility), m_groupPolicy(groupPolicy), m_adminSetting(adminSetting) {} + Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Settings::ExperimentalFeature::Feature feature, Settings::TogglePolicy::Policy groupPolicy, Settings::BoolAdminSetting adminSetting) : + m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type), m_feature(feature), m_groupPolicy(groupPolicy), m_adminSetting(adminSetting) {} + ArgumentCommon m_argCommon; Resource::StringId m_desc; bool m_required = false; @@ -251,6 +255,6 @@ namespace AppInstaller::CLI size_t m_countLimit = 1; Settings::ExperimentalFeature::Feature m_feature = Settings::ExperimentalFeature::Feature::None; Settings::TogglePolicy::Policy m_groupPolicy = Settings::TogglePolicy::Policy::None; - Settings::AdminSetting m_adminSetting = Settings::AdminSetting::Unknown; + Settings::BoolAdminSetting m_adminSetting = Settings::BoolAdminSetting::Unknown; }; } diff --git a/src/AppInstallerCLICore/Command.cpp b/src/AppInstallerCLICore/Command.cpp index dec1945adf..408b7adfe7 100644 --- a/src/AppInstallerCLICore/Command.cpp +++ b/src/AppInstallerCLICore/Command.cpp @@ -637,7 +637,7 @@ namespace AppInstaller::CLI throw GroupPolicyException(arg.GroupPolicy()); } - if (arg.AdminSetting() != AdminSetting::Unknown && !Settings::IsAdminSettingEnabled(arg.AdminSetting()) && execArgs.Contains(arg.ExecArgType())) + if (arg.AdminSetting() != BoolAdminSetting::Unknown && !Settings::IsAdminSettingEnabled(arg.AdminSetting()) && execArgs.Contains(arg.ExecArgType())) { auto setting = Settings::AdminSettingToString(arg.AdminSetting()); AICLI_LOG(CLI, Error, << "Trying to use argument: " << arg.Name() << " disabled by admin setting " << setting); diff --git a/src/AppInstallerCLICore/Commands/DownloadCommand.cpp b/src/AppInstallerCLICore/Commands/DownloadCommand.cpp index 39739feeaf..b2b7d3ec15 100644 --- a/src/AppInstallerCLICore/Commands/DownloadCommand.cpp +++ b/src/AppInstallerCLICore/Commands/DownloadCommand.cpp @@ -36,8 +36,8 @@ namespace AppInstaller::CLI Argument::ForType(Args::Type::CustomHeader), Argument::ForType(Args::Type::AuthenticationMode), Argument::ForType(Args::Type::AuthenticationAccount), - Argument::ForType(Execution::Args::Type::AcceptPackageAgreements), - Argument::ForType(Execution::Args::Type::AcceptSourceAgreements), + Argument::ForType(Args::Type::AcceptPackageAgreements), + Argument::ForType(Args::Type::AcceptSourceAgreements), }; } diff --git a/src/AppInstallerCLICore/Commands/RootCommand.cpp b/src/AppInstallerCLICore/Commands/RootCommand.cpp index fc0c6b7cb3..f5a61d79fa 100644 --- a/src/AppInstallerCLICore/Commands/RootCommand.cpp +++ b/src/AppInstallerCLICore/Commands/RootCommand.cpp @@ -124,13 +124,21 @@ namespace AppInstaller::CLI Execution::TableOutput<2> adminSettingsTable{ context.Reporter, { Resource::String::AdminSettingHeader, Resource::String::StateHeader } }; // Output the admin settings. - for (const auto& setting : Settings::GetAllAdminSettings()) + for (const auto& setting : Settings::GetAllBoolAdminSettings()) { adminSettingsTable.OutputLine({ std::string{ AdminSettingToString(setting)}, Resource::LocString{ IsAdminSettingEnabled(setting) ? Resource::String::StateEnabled : Resource::String::StateDisabled } }); } + for (const auto& setting : Settings::GetAllStringAdminSettings()) + { + auto settingValue = GetAdminSetting(setting); + adminSettingsTable.OutputLine({ + std::string{ AdminSettingToString(setting)}, + settingValue ? Utility::LocIndString{ settingValue.value() } : Resource::LocString{ Resource::String::StateDisabled } + }); + } adminSettingsTable.Complete(); } diff --git a/src/AppInstallerCLICore/Commands/SettingsCommand.cpp b/src/AppInstallerCLICore/Commands/SettingsCommand.cpp index 55c436e631..70620f5bca 100644 --- a/src/AppInstallerCLICore/Commands/SettingsCommand.cpp +++ b/src/AppInstallerCLICore/Commands/SettingsCommand.cpp @@ -20,6 +20,8 @@ namespace AppInstaller::CLI { return InitializeFromMoveOnly>>({ std::make_unique(FullName()), + std::make_unique(FullName()), + std::make_unique(FullName()), }); } @@ -49,21 +51,20 @@ namespace AppInstaller::CLI void SettingsCommand::ValidateArgumentsInternal(Execution::Args& execArgs) const { // Get admin setting string for all available options except Unknown - using AdminSetting_t = std::underlying_type_t; std::vector adminSettingList; - for (AdminSetting_t i = 1 + static_cast(AdminSetting::Unknown); i < static_cast(AdminSetting::Max); ++i) + for (auto setting : GetAllSequentialEnumValues(BoolAdminSetting::Unknown)) { - adminSettingList.emplace_back(AdminSettingToString(static_cast(i))); + adminSettingList.emplace_back(AdminSettingToString(setting)); } Utility::LocIndString validOptions = Join(", "_liv, adminSettingList); - if (execArgs.Contains(Execution::Args::Type::AdminSettingEnable) && AdminSetting::Unknown == StringToAdminSetting(execArgs.GetArg(Execution::Args::Type::AdminSettingEnable))) + if (execArgs.Contains(Execution::Args::Type::AdminSettingEnable) && BoolAdminSetting::Unknown == StringToBoolAdminSetting(execArgs.GetArg(Execution::Args::Type::AdminSettingEnable))) { throw CommandException(Resource::String::InvalidArgumentValueError(ArgumentCommon::ForType(Execution::Args::Type::AdminSettingEnable).Name, validOptions)); } - if (execArgs.Contains(Execution::Args::Type::AdminSettingDisable) && AdminSetting::Unknown == StringToAdminSetting(execArgs.GetArg(Execution::Args::Type::AdminSettingDisable))) + if (execArgs.Contains(Execution::Args::Type::AdminSettingDisable) && BoolAdminSetting::Unknown == StringToBoolAdminSetting(execArgs.GetArg(Execution::Args::Type::AdminSettingDisable))) { throw CommandException(Resource::String::InvalidArgumentValueError(ArgumentCommon::ForType(Execution::Args::Type::AdminSettingDisable).Name, validOptions)); } @@ -110,4 +111,103 @@ namespace AppInstaller::CLI context << Workflow::ExportSettings; } + + std::vector SettingsSetCommand::GetArguments() const + { + return { + Argument { Execution::Args::Type::SettingName, Resource::String::SettingNameArgumentDescription, ArgumentType::Positional, true }, + Argument { Execution::Args::Type::SettingValue, Resource::String::SettingValueArgumentDescription, ArgumentType::Positional, true }, + }; + } + + Resource::LocString SettingsSetCommand::ShortDescription() const + { + return { Resource::String::SettingsSetCommandShortDescription }; + } + + Resource::LocString SettingsSetCommand::LongDescription() const + { + return { Resource::String::SettingsSetCommandLongDescription }; + } + + Utility::LocIndView SettingsSetCommand::HelpLink() const + { + return s_SettingsCommand_HelpLink; + } + + void SettingsSetCommand::ValidateArgumentsInternal(Execution::Args& execArgs) const + { + // Get admin setting string for all available options except Unknown + std::vector adminSettingList; + for (auto setting : GetAllSequentialEnumValues(StringAdminSetting::Unknown)) + { + adminSettingList.emplace_back(AdminSettingToString(setting)); + } + + Utility::LocIndString validOptions = Join(", "_liv, adminSettingList); + + if (StringAdminSetting::Unknown == StringToStringAdminSetting(execArgs.GetArg(Execution::Args::Type::SettingName))) + { + throw CommandException(Resource::String::InvalidArgumentValueError(ArgumentCommon::ForType(Execution::Args::Type::SettingName).Name, validOptions)); + } + } + + void SettingsSetCommand::ExecuteInternal(Execution::Context& context) const + { + context << + Workflow::EnsureRunningAsAdmin << + Workflow::SetAdminSetting; + } + + std::vector SettingsResetCommand::GetArguments() const + { + return { + Argument { Execution::Args::Type::SettingName, Resource::String::SettingNameArgumentDescription, ArgumentType::Positional, true }, + }; + } + + Resource::LocString SettingsResetCommand::ShortDescription() const + { + return { Resource::String::SettingsResetCommandShortDescription }; + } + + Resource::LocString SettingsResetCommand::LongDescription() const + { + return { Resource::String::SettingsResetCommandLongDescription }; + } + + Utility::LocIndView SettingsResetCommand::HelpLink() const + { + return s_SettingsCommand_HelpLink; + } + + void SettingsResetCommand::ValidateArgumentsInternal(Execution::Args& execArgs) const + { + // Get admin setting string for all available options except Unknown. + // We accept both bool and string settings + std::vector adminSettingList; + for (auto setting : GetAllSequentialEnumValues(BoolAdminSetting::Unknown)) + { + adminSettingList.emplace_back(AdminSettingToString(setting)); + } + for (auto setting : GetAllSequentialEnumValues(StringAdminSetting::Unknown)) + { + adminSettingList.emplace_back(AdminSettingToString(setting)); + } + + Utility::LocIndString validOptions = Join(", "_liv, adminSettingList); + + if (StringAdminSetting::Unknown == StringToStringAdminSetting(execArgs.GetArg(Execution::Args::Type::SettingName)) + && BoolAdminSetting::Unknown == StringToBoolAdminSetting(execArgs.GetArg(Execution::Args::Type::SettingName))) + { + throw CommandException(Resource::String::InvalidArgumentValueError(ArgumentCommon::ForType(Execution::Args::Type::SettingName).Name, validOptions)); + } + } + + void SettingsResetCommand::ExecuteInternal(Execution::Context& context) const + { + context << + Workflow::EnsureRunningAsAdmin << + Workflow::ResetAdminSetting; + } } diff --git a/src/AppInstallerCLICore/Commands/SettingsCommand.h b/src/AppInstallerCLICore/Commands/SettingsCommand.h index aee6cffbfd..78cb164da2 100644 --- a/src/AppInstallerCLICore/Commands/SettingsCommand.h +++ b/src/AppInstallerCLICore/Commands/SettingsCommand.h @@ -34,4 +34,36 @@ namespace AppInstaller::CLI protected: void ExecuteInternal(Execution::Context& context) const override; }; + + struct SettingsSetCommand final : public Command + { + SettingsSetCommand(std::string_view parent) : Command("set", {}, parent, Settings::TogglePolicy::Policy::Settings) {} + + std::vector GetArguments() const override; + + virtual Resource::LocString ShortDescription() const override; + virtual Resource::LocString LongDescription() const override; + + Utility::LocIndView HelpLink() const override; + + protected: + void ValidateArgumentsInternal(Execution::Args& execArgs) const override; + void ExecuteInternal(Execution::Context& context) const override; + }; + + struct SettingsResetCommand final : public Command + { + SettingsResetCommand(std::string_view parent) : Command("reset", {}, parent, Settings::TogglePolicy::Policy::Settings) {} + + std::vector GetArguments() const override; + + virtual Resource::LocString ShortDescription() const override; + virtual Resource::LocString LongDescription() const override; + + Utility::LocIndView HelpLink() const override; + + protected: + void ValidateArgumentsInternal(Execution::Args& execArgs) const override; + void ExecuteInternal(Execution::Context& context) const override; + }; } diff --git a/src/AppInstallerCLICore/Core.cpp b/src/AppInstallerCLICore/Core.cpp index 89d5c892eb..fe19bb0aec 100644 --- a/src/AppInstallerCLICore/Core.cpp +++ b/src/AppInstallerCLICore/Core.cpp @@ -119,13 +119,6 @@ namespace AppInstaller::CLI Logging::Telemetry().LogCommand(command->FullName()); command->ParseArguments(invocation, context.Args); - - // Change logging level to Info if Verbose not requested - if (context.Args.Contains(Execution::Args::Type::VerboseLogs)) - { - Logging::Log().SetLevel(Logging::Level::Verbose); - } - context.UpdateForArgs(); context.SetExecutingCommand(command.get()); command->ValidateArguments(context.Args); diff --git a/src/AppInstallerCLICore/ExecutionArgs.h b/src/AppInstallerCLICore/ExecutionArgs.h index ad1b70496a..8ea1e0754d 100644 --- a/src/AppInstallerCLICore/ExecutionArgs.h +++ b/src/AppInstallerCLICore/ExecutionArgs.h @@ -89,6 +89,8 @@ namespace AppInstaller::CLI::Execution // Setting Command AdminSettingEnable, AdminSettingDisable, + SettingName, + SettingValue, // Upgrade command All, // Used in Update command to update all installed packages to latest @@ -140,6 +142,10 @@ namespace AppInstaller::CLI::Execution AuthenticationMode, // Authentication mode (silent, silentPreferred or interactive) AuthenticationAccount, // Authentication account to be used + // Network Behavior + Proxy, // Set a proxy to use in this execution + NoProxy, // Do not use the default proxy + ToolVersion, // Used for demonstration purposes diff --git a/src/AppInstallerCLICore/ExecutionContext.cpp b/src/AppInstallerCLICore/ExecutionContext.cpp index 48fd668ee6..d8ecb88b1c 100644 --- a/src/AppInstallerCLICore/ExecutionContext.cpp +++ b/src/AppInstallerCLICore/ExecutionContext.cpp @@ -9,6 +9,7 @@ #include #include #include +#include using namespace AppInstaller::Checkpoints; @@ -349,6 +350,23 @@ namespace AppInstaller::CLI::Execution void Context::UpdateForArgs() { + // Change logging level to Info if Verbose not requested + if (Args.Contains(Args::Type::VerboseLogs)) + { + Logging::Log().SetLevel(Logging::Level::Verbose); + } + + // Set proxy + if (Args.Contains(Args::Type::Proxy)) + { + Network().SetProxyUri(std::string{ Args.GetArg(Args::Type::Proxy) }); + } + else if (Args.Contains(Args::Type::NoProxy)) + { + Network().SetProxyUri(std::nullopt); + } + + // Set visual style if (Args.Contains(Args::Type::NoVT)) { Reporter.SetStyle(VisualStyle::NoVT); diff --git a/src/AppInstallerCLICore/ExecutionContextData.h b/src/AppInstallerCLICore/ExecutionContextData.h index e19b8d7233..b1f5e42110 100644 --- a/src/AppInstallerCLICore/ExecutionContextData.h +++ b/src/AppInstallerCLICore/ExecutionContextData.h @@ -276,6 +276,7 @@ namespace AppInstaller::CLI::Execution using value_t = std::string; }; + template<> struct DataMapping { diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index 65bb45e870..a05c3c691a 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -339,15 +339,16 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(NestedInstallerNotFound); WINGET_DEFINE_RESOURCE_STRINGID(NestedInstallerNotSpecified); WINGET_DEFINE_RESOURCE_STRINGID(NestedInstallerNotSupported); - WINGET_DEFINE_RESOURCE_STRINGID(NoApplicableInstallers); WINGET_DEFINE_RESOURCE_STRINGID(NoAdminRepairForUserScopePackage); + WINGET_DEFINE_RESOURCE_STRINGID(NoApplicableInstallers); WINGET_DEFINE_RESOURCE_STRINGID(NoExperimentalFeaturesMessage); WINGET_DEFINE_RESOURCE_STRINGID(NoInstalledPackageFound); WINGET_DEFINE_RESOURCE_STRINGID(NoPackageFound); WINGET_DEFINE_RESOURCE_STRINGID(NoPackageSelectionArgumentProvided); WINGET_DEFINE_RESOURCE_STRINGID(NoPackagesFoundInImportFile); - WINGET_DEFINE_RESOURCE_STRINGID(Notes); + WINGET_DEFINE_RESOURCE_STRINGID(NoProxyArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(NoRepairInfoFound); + WINGET_DEFINE_RESOURCE_STRINGID(Notes); WINGET_DEFINE_RESOURCE_STRINGID(NoUninstallInfoFound); WINGET_DEFINE_RESOURCE_STRINGID(NoUpgradeArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(NoVTArgumentDescription); @@ -414,6 +415,7 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(PromptOptionNo); WINGET_DEFINE_RESOURCE_STRINGID(PromptOptionYes); WINGET_DEFINE_RESOURCE_STRINGID(PromptToProceed); + WINGET_DEFINE_RESOURCE_STRINGID(ProxyArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(PurgeArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(PurgeInstallDirectory); WINGET_DEFINE_RESOURCE_STRINGID(QueryArgumentDescription); @@ -437,6 +439,8 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(ReportIdentityFound); WINGET_DEFINE_RESOURCE_STRINGID(RequiredArgError); WINGET_DEFINE_RESOURCE_STRINGID(ReservedFilenameError); + WINGET_DEFINE_RESOURCE_STRINGID(ResetAdminSettingFailed); + WINGET_DEFINE_RESOURCE_STRINGID(ResetAdminSettingSucceeded); WINGET_DEFINE_RESOURCE_STRINGID(ResumeCommandLongDescription); WINGET_DEFINE_RESOURCE_STRINGID(ResumeCommandShortDescription); WINGET_DEFINE_RESOURCE_STRINGID(ResumeIdArgumentDescription); @@ -457,14 +461,22 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(SearchTruncated); WINGET_DEFINE_RESOURCE_STRINGID(SearchVersion); WINGET_DEFINE_RESOURCE_STRINGID(SeeLineAndColumn); + WINGET_DEFINE_RESOURCE_STRINGID(SetAdminSettingFailed); + WINGET_DEFINE_RESOURCE_STRINGID(SetAdminSettingSucceeded); WINGET_DEFINE_RESOURCE_STRINGID(SettingLoadFailure); + WINGET_DEFINE_RESOURCE_STRINGID(SettingNameArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(SettingsCommandLongDescription); WINGET_DEFINE_RESOURCE_STRINGID(SettingsCommandShortDescription); WINGET_DEFINE_RESOURCE_STRINGID(SettingsExportCommandLongDescription); WINGET_DEFINE_RESOURCE_STRINGID(SettingsExportCommandShortDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SettingsResetCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SettingsResetCommandShortDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SettingsSetCommandLongDescription); + WINGET_DEFINE_RESOURCE_STRINGID(SettingsSetCommandShortDescription); WINGET_DEFINE_RESOURCE_STRINGID(SettingsWarningField); WINGET_DEFINE_RESOURCE_STRINGID(SettingsWarnings); WINGET_DEFINE_RESOURCE_STRINGID(SettingsWarningValue); + WINGET_DEFINE_RESOURCE_STRINGID(SettingValueArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(ShowChannel); WINGET_DEFINE_RESOURCE_STRINGID(ShowCommandLongDescription); WINGET_DEFINE_RESOURCE_STRINGID(ShowCommandShortDescription); @@ -589,8 +601,8 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(UpdateNotApplicableReason); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeAvailableForPinned); - WINGET_DEFINE_RESOURCE_STRINGID(UpgradeBlockedByPinCount); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeBlockedByManifest); + WINGET_DEFINE_RESOURCE_STRINGID(UpgradeBlockedByPinCount); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeCommandLongDescription); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeCommandShortDescription); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeDifferentInstallTechnology); diff --git a/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp b/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp index c273fd827a..069598e45b 100644 --- a/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/ArchiveFlow.cpp @@ -29,7 +29,7 @@ namespace AppInstaller::CLI::Workflow else { if (context.Args.Contains(Execution::Args::Type::IgnoreLocalArchiveMalwareScan) && - Settings::IsAdminSettingEnabled(Settings::AdminSetting::LocalArchiveMalwareScanOverride)) + Settings::IsAdminSettingEnabled(Settings::BoolAdminSetting::LocalArchiveMalwareScanOverride)) { AICLI_LOG(CLI, Warning, << "Archive scan detected malware. Proceeding due to --ignore-local-archive-malware-scan"); context.Reporter.Warn() << Resource::String::ArchiveFailedMalwareScanOverridden << std::endl; diff --git a/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp b/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp index 1bd4cd462a..618db03789 100644 --- a/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp @@ -7,13 +7,16 @@ #include #include #include +#include #include +#include namespace AppInstaller::CLI::Workflow { using namespace AppInstaller::Manifest; using namespace AppInstaller::Repository; using namespace AppInstaller::Utility; + using namespace AppInstaller::Settings; using namespace std::string_view_literals; namespace @@ -211,14 +214,18 @@ namespace AppInstaller::CLI::Workflow context << DownloadInstallerFile; break; case InstallerTypeEnum::Msix: - if (installer.SignatureSha256.empty() || installerDownloadOnly) + // If the signature hash is provided in the manifest and we are doing an install, + // we can just verify signature hash without a full download and do a streaming install. + // Even if we have the signature hash, we still do a full download if InstallerDownloadOnly + // flag is set, or if we need to use a proxy (as deployment APIs won't use proxy for us). + if (installer.SignatureSha256.empty() + || installerDownloadOnly + || Network().GetProxyUri()) { - // If InstallerDownloadOnly flag is set, always download the installer file. context << DownloadInstallerFile; } else { - // Signature hash provided. No download needed. Just verify signature hash. context << GetMsixSignatureHash; } break; @@ -386,6 +393,7 @@ namespace AppInstaller::CLI::Workflow { const auto& installer = context.Get().value(); + // Signature hash is only used for streaming installs, which don't use proxy Msix::MsixInfo msixInfo(installer.Url); auto signatureHash = msixInfo.GetSignatureHash(); @@ -422,7 +430,7 @@ namespace AppInstaller::CLI::Workflow { context.Reporter.Error() << Resource::String::InstallerHashMismatchAdminBlock << std::endl; } - else if (!Settings::IsAdminSettingEnabled(Settings::AdminSetting::InstallerHashOverride)) + else if (!Settings::IsAdminSettingEnabled(Settings::BoolAdminSetting::InstallerHashOverride)) { context.Reporter.Error() << Resource::String::InstallerHashMismatchError << std::endl; } diff --git a/src/AppInstallerCLICore/Workflows/SettingsFlow.cpp b/src/AppInstallerCLICore/Workflows/SettingsFlow.cpp index da2d5c8198..49eca405cd 100644 --- a/src/AppInstallerCLICore/Workflows/SettingsFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/SettingsFlow.cpp @@ -23,12 +23,22 @@ namespace AppInstaller::CLI::Workflow root["userSettingsFile"] = UserSettings::SettingsFilePath().u8string(); } - void AddAdminSetting(AdminSetting setting) + void AddAdminSetting(BoolAdminSetting setting) { auto str = std::string{ Settings::AdminSettingToString(setting) }; root["adminSettings"][str] = Settings::IsAdminSettingEnabled(setting); } + void AddAdminSetting(StringAdminSetting setting) + { + auto name = std::string{ Settings::AdminSettingToString(setting) }; + auto value = Settings::GetAdminSetting(setting); + if (value) + { + root["adminSettings"][name] = value.value(); + } + } + std::string ToJsonString() const { Json::StreamWriterBuilder writerBuilder; @@ -44,7 +54,7 @@ namespace AppInstaller::CLI::Workflow void EnableAdminSetting(Execution::Context& context) { auto adminSettingString = context.Args.GetArg(Execution::Args::Type::AdminSettingEnable); - AdminSetting adminSetting = Settings::StringToAdminSetting(adminSettingString); + BoolAdminSetting adminSetting = Settings::StringToBoolAdminSetting(adminSettingString); if (Settings::EnableAdminSetting(adminSetting)) { context.Reporter.Info() << Resource::String::AdminSettingEnabled(AdminSettingToString(adminSetting)) << std::endl; @@ -58,7 +68,7 @@ namespace AppInstaller::CLI::Workflow void DisableAdminSetting(Execution::Context& context) { auto adminSettingString = context.Args.GetArg(Execution::Args::Type::AdminSettingDisable); - AdminSetting adminSetting = Settings::StringToAdminSetting(adminSettingString); + BoolAdminSetting adminSetting = Settings::StringToBoolAdminSetting(adminSettingString); if (Settings::DisableAdminSetting(adminSetting)) { context.Reporter.Info() << Resource::String::AdminSettingDisabled(AdminSettingToString(adminSetting)) << std::endl; @@ -69,6 +79,40 @@ namespace AppInstaller::CLI::Workflow } } + void SetAdminSetting(Execution::Context& context) + { + auto adminSettingName = context.Args.GetArg(Execution::Args::Type::SettingName); + auto adminSettingValue = context.Args.GetArg(Execution::Args::Type::SettingValue); + StringAdminSetting adminSetting = Settings::StringToStringAdminSetting(adminSettingName); + if (Settings::SetAdminSetting(adminSetting, adminSettingValue)) + { + context.Reporter.Info() << Resource::String::SetAdminSettingSucceeded(LocIndString{ adminSettingName }, LocIndString{ adminSettingValue }) << std::endl; + } + else + { + context.Reporter.Error() << Resource::String::SetAdminSettingFailed(LocIndString{ adminSettingName }) << std::endl; + } + } + + void ResetAdminSetting(Execution::Context& context) + { + auto adminSettingName = context.Args.GetArg(Execution::Args::Type::SettingName); + + // Try as both bool and string setting as we don't know the type + auto boolAdminSetting = Settings::StringToBoolAdminSetting(adminSettingName); + auto stringAdminSetting = Settings::StringToStringAdminSetting(adminSettingName); + + if ((boolAdminSetting != Settings::BoolAdminSetting::Unknown && Settings::DisableAdminSetting(boolAdminSetting)) + || (stringAdminSetting != Settings::StringAdminSetting::Unknown && Settings::ResetAdminSetting(stringAdminSetting))) + { + context.Reporter.Info() << Resource::String::ResetAdminSettingSucceeded(LocIndString{ adminSettingName }) << std::endl; + } + else + { + context.Reporter.Error() << Resource::String::ResetAdminSettingFailed(LocIndString{ adminSettingName }) << std::endl; + } + } + void OpenUserSetting(Execution::Context& context) { // Show warnings only when the setting command is executed. @@ -129,7 +173,12 @@ namespace AppInstaller::CLI::Workflow { ExportSettingsJson exportSettingsJson; - for (const auto& setting : GetAllAdminSettings()) + for (const auto& setting : GetAllBoolAdminSettings()) + { + exportSettingsJson.AddAdminSetting(setting); + } + + for (const auto& setting : GetAllStringAdminSettings()) { exportSettingsJson.AddAdminSetting(setting); } diff --git a/src/AppInstallerCLICore/Workflows/SettingsFlow.h b/src/AppInstallerCLICore/Workflows/SettingsFlow.h index e40a0051c9..50998295a5 100644 --- a/src/AppInstallerCLICore/Workflows/SettingsFlow.h +++ b/src/AppInstallerCLICore/Workflows/SettingsFlow.h @@ -17,6 +17,18 @@ namespace AppInstaller::CLI::Workflow // Outputs: None void DisableAdminSetting(Execution::Context& context); + // Sets the value of an admin setting. + // Required Args: SettingName, SettingValue + // Inputs: None + // Outputs: None + void SetAdminSetting(Execution::Context& context); + + // Resets an admin setting to the default. + // Required Args: SettingName + // Inputs: None + // Outputs: None + void ResetAdminSetting(Execution::Context& context); + // Opens the user settings. // Required Args: None // Inputs: None diff --git a/src/AppInstallerCLIE2ETests/GroupPolicyHelper.cs b/src/AppInstallerCLIE2ETests/GroupPolicyHelper.cs index 2eb2fe0db6..8179934fa6 100644 --- a/src/AppInstallerCLIE2ETests/GroupPolicyHelper.cs +++ b/src/AppInstallerCLIE2ETests/GroupPolicyHelper.cs @@ -118,6 +118,11 @@ private GroupPolicyHelper(string name, string elementId) /// public static GroupPolicyHelper EnableConfiguration { get; private set; } = new GroupPolicyHelper("EnableWindowsPackageManagerConfiguration"); + /// + /// Gets the Enable Windows Package Manager proxy command line options policy. + /// + public static GroupPolicyHelper EnableProxyCommandLineOptions { get; private set; } = new GroupPolicyHelper("EnableWindowsPackageManagerProxyCommandLineOptions"); + /// /// Gets the Enable auto update interval policy. /// @@ -138,6 +143,7 @@ private GroupPolicyHelper(string name, string elementId) SourceAutoUpdateInterval, EnableWinGetCommandLineInterfaces, EnableConfiguration, + EnableProxyCommandLineOptions, }; /// diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw index eba36a6e48..7f5838c20e 100644 --- a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw +++ b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -2817,4 +2817,48 @@ Please specify one of them using the --source option to proceed. The SQLite connection was terminated to prevent corruption. + + Enable Windows Package Manager proxy command line options + Describes a Group Policy that can enable the use of the --proxy option to set a proxy + + + Set a proxy to use for this execution + + + Disable the use of proxy for this execution + + + Cannot reset {0}. This setting is controlled by policy. For more information contact your system administrator. + {Locked="{0}"} The value will be replaced with the feature name + + + Reset admin setting '{0}'. + {Locked="{0}"} Message displayed after the user resets an admin setting to its default value. Reset is used as verb in past tense. {0} is a placeholder replaced by the setting name. + + + Cannot set {0}. This setting is controlled by policy. For more information contact your system administrator. + {Locked="{0}"} The value will be replaced with the feature name + + + Set admin setting '{0}' to '{1}'. + {Locked="{0}"} Message displayed after the user sets the value of an admin setting. Set is used as a verb in past tense. {0} is a placeholder replaced by the setting name. {1} is a placeholder replaced + + + Name of the setting to modify + + + Value to set for the setting. + + + Resets an admin setting to its default value. + + + Resets an admin setting to its default value. + + + Sets the value of an admin setting. + + + Sets the value of an admin setting. + \ No newline at end of file diff --git a/src/AppInstallerCLITests/AdminSettings.cpp b/src/AppInstallerCLITests/AdminSettings.cpp index be05f13e71..a7fa9d2a15 100644 --- a/src/AppInstallerCLITests/AdminSettings.cpp +++ b/src/AppInstallerCLITests/AdminSettings.cpp @@ -16,21 +16,21 @@ TEST_CASE("AdminSetting_Enable", "[adminSettings]") { GroupPolicyTestOverride policies; policies.SetState(TogglePolicy::Policy::LocalManifestFiles, PolicyState::NotConfigured); - REQUIRE(EnableAdminSetting(AdminSetting::LocalManifestFiles)); + REQUIRE(EnableAdminSetting(BoolAdminSetting::LocalManifestFiles)); } SECTION("Enabled") { GroupPolicyTestOverride policies; policies.SetState(TogglePolicy::Policy::LocalManifestFiles, PolicyState::Enabled); - REQUIRE(EnableAdminSetting(AdminSetting::LocalManifestFiles)); + REQUIRE(EnableAdminSetting(BoolAdminSetting::LocalManifestFiles)); } SECTION("Disabled") { GroupPolicyTestOverride policies; policies.SetState(TogglePolicy::Policy::LocalManifestFiles, PolicyState::Disabled); - REQUIRE_FALSE(EnableAdminSetting(AdminSetting::LocalManifestFiles)); + REQUIRE_FALSE(EnableAdminSetting(BoolAdminSetting::LocalManifestFiles)); } } } @@ -43,21 +43,42 @@ TEST_CASE("AdminSetting_Disable", "[adminSettings]") { GroupPolicyTestOverride policies; policies.SetState(TogglePolicy::Policy::LocalManifestFiles, PolicyState::NotConfigured); - REQUIRE(DisableAdminSetting(AdminSetting::LocalManifestFiles)); + REQUIRE(DisableAdminSetting(BoolAdminSetting::LocalManifestFiles)); } SECTION("Enabled") { GroupPolicyTestOverride policies; policies.SetState(TogglePolicy::Policy::LocalManifestFiles, PolicyState::Enabled); - REQUIRE_FALSE(DisableAdminSetting(AdminSetting::LocalManifestFiles)); + REQUIRE_FALSE(DisableAdminSetting(BoolAdminSetting::LocalManifestFiles)); } SECTION("Disabled") { GroupPolicyTestOverride policies; policies.SetState(TogglePolicy::Policy::LocalManifestFiles, PolicyState::Disabled); - REQUIRE(DisableAdminSetting(AdminSetting::LocalManifestFiles)); + REQUIRE(DisableAdminSetting(BoolAdminSetting::LocalManifestFiles)); } } } + +TEST_CASE("AdminSetting_AllSettingsAreImplemented", "[adminSettings]") +{ + for (auto adminSetting : GetAllBoolAdminSettings()) + { + // If we forget to add it to the conversion, it returns Unknown/None + REQUIRE(AdminSettingToString(adminSetting) != AdminSettingToString(BoolAdminSetting::Unknown)); + REQUIRE(StringToBoolAdminSetting(AdminSettingToString(adminSetting)) != BoolAdminSetting::Unknown); + REQUIRE(GetAdminSettingPolicy(adminSetting) != TogglePolicy::Policy::None); + + GroupPolicyTestOverride policies; + policies.SetState(GetAdminSettingPolicy(adminSetting), PolicyState::NotConfigured); + + // We should be able to configure the state. + // If we forget to add it, it won't persist. + REQUIRE(EnableAdminSetting(adminSetting)); + REQUIRE(IsAdminSettingEnabled(adminSetting)); + REQUIRE(DisableAdminSetting(adminSetting)); + REQUIRE_FALSE(IsAdminSettingEnabled(adminSetting)); + } +} \ No newline at end of file diff --git a/src/AppInstallerCLITests/CustomHeader.cpp b/src/AppInstallerCLITests/CustomHeader.cpp index a8f3a2bf7a..1501d4cd95 100644 --- a/src/AppInstallerCLITests/CustomHeader.cpp +++ b/src/AppInstallerCLITests/CustomHeader.cpp @@ -54,7 +54,7 @@ TEST_CASE("RestClient_CustomHeader", "[RestSource][CustomHeader]") std::optional customHeader = "Testing custom header"; auto header = std::make_pair<>(CustomHeaderName, JSON::GetUtilityString(customHeader.value())); HttpClientHelper helper{ GetHeaderVerificationHandler(web::http::status_codes::OK, sample, header) }; - RestClient client = RestClient::Create(utility::conversions::to_utf8string("https://restsource.com/api"), customHeader, {}, {}, std::move(helper)); + RestClient client = RestClient::Create(utility::conversions::to_utf8string("https://restsource.com/api"), customHeader, {}, std::move(helper), {}); REQUIRE(client.GetSourceIdentifier() == "Source123"); } @@ -66,7 +66,7 @@ TEST_CASE("RestSourceSearch_CustomHeader", "[RestSource][CustomHeader]") std::unordered_map headers; headers.emplace(CustomHeaderName, customHeader); - V1_1::Interface v1_1{ "https://restsource.com/api", {}, headers, std::move(helper) }; + V1_1::Interface v1_1{ "https://restsource.com/api", std::move(helper) , {}, headers}; Schema::IRestClient::SearchResult searchResponse = v1_1.Search({}); REQUIRE(searchResponse.Matches.size() == 1); Schema::IRestClient::Package package = searchResponse.Matches.at(0); @@ -80,7 +80,7 @@ TEST_CASE("RestSourceSearch_WhitespaceCustomHeader", "[RestSource][CustomHeader] std::unordered_map headers; headers.emplace(CustomHeaderName, customHeader); - V1_1::Interface v1_1{ "https://restsource.com/api", {}, headers, std::move(helper) }; + V1_1::Interface v1_1{ "https://restsource.com/api", std::move(helper), {}, headers }; Schema::IRestClient::SearchResult searchResponse = v1_1.Search({}); REQUIRE(searchResponse.Matches.size() == 1); } @@ -93,7 +93,7 @@ TEST_CASE("RestSourceSearch_NoCustomHeader", "[RestSource][CustomHeader]") std::unordered_map headers; headers.emplace(CustomHeaderName, customHeader); - V1_1::Interface v1_1{ "https://restsource.com/api", {}, {}, std::move(helper) }; + V1_1::Interface v1_1{ "https://restsource.com/api", std::move(helper), {}, {} }; REQUIRE_THROWS_HR(v1_1.Search({}), APPINSTALLER_CLI_ERROR_RESTSOURCE_INTERNAL_ERROR); } @@ -103,7 +103,7 @@ TEST_CASE("RestSourceSearch_CustomHeaderExceedingSize", "[RestSource][CustomHead auto header = std::make_pair<>(CustomHeaderName, JSON::GetUtilityString(customHeader)); HttpClientHelper helper{ GetHeaderVerificationHandler(web::http::status_codes::OK, sampleSearchResponse, header) }; - REQUIRE_THROWS_HR(RestClient::Create(utility::conversions::to_utf8string("https://restsource.com/api"), customHeader, {}, {}, std::move(helper)), + REQUIRE_THROWS_HR(RestClient::Create(utility::conversions::to_utf8string("https://restsource.com/api"), customHeader, {}, std::move(helper), {}), APPINSTALLER_CLI_ERROR_CUSTOMHEADER_EXCEEDS_MAXLENGTH); } @@ -121,7 +121,7 @@ TEST_CASE("RestClient_CustomUserAgentHeader", "[RestSource][CustomHeader]") std::string testCaller = "TestCaller"; auto header = std::make_pair<>(web::http::header_names::user_agent, JSON::GetUtilityString(Runtime::GetUserAgent(testCaller))); HttpClientHelper helper{ GetHeaderVerificationHandler(web::http::status_codes::OK, sample, header) }; - RestClient client = RestClient::Create(utility::conversions::to_utf8string("https://restsource.com/api"), {}, testCaller, {}, std::move(helper)); + RestClient client = RestClient::Create(utility::conversions::to_utf8string("https://restsource.com/api"), {}, testCaller, std::move(helper), {}); REQUIRE(client.GetSourceIdentifier() == "Source123"); } @@ -138,6 +138,6 @@ TEST_CASE("RestClient_DefaultUserAgentHeader", "[RestSource][CustomHeader]") auto header = std::make_pair<>(web::http::header_names::user_agent, JSON::GetUtilityString(Runtime::GetDefaultUserAgent())); HttpClientHelper helper{ GetHeaderVerificationHandler(web::http::status_codes::OK, sample, header) }; - RestClient client = RestClient::Create(utility::conversions::to_utf8string("https://restsource.com/api"), {}, {}, {}, std::move(helper)); + RestClient client = RestClient::Create(utility::conversions::to_utf8string("https://restsource.com/api"), {}, {}, std::move(helper), {}); REQUIRE(client.GetSourceIdentifier() == "Source123"); } \ No newline at end of file diff --git a/src/AppInstallerCLITests/GroupPolicy.cpp b/src/AppInstallerCLITests/GroupPolicy.cpp index f57442c28f..4c8c2356ac 100644 --- a/src/AppInstallerCLITests/GroupPolicy.cpp +++ b/src/AppInstallerCLITests/GroupPolicy.cpp @@ -376,6 +376,7 @@ TEST_CASE("GroupPolicy_AllEnabled", "[groupPolicy]") SetRegistryValue(policiesKey.get(), BypassCertificatePinningForMicrosoftStoreValueName, 1); SetRegistryValue(policiesKey.get(), EnableWindowsPackageManagerCommandLineInterfaces, 1); SetRegistryValue(policiesKey.get(), ConfigurationPolicyValueName, 1); + SetRegistryValue(policiesKey.get(), ProxyCommandLineOptionsPolicyValueName, 1); GroupPolicy groupPolicy{ policiesKey.get() }; for (const auto& policy : TogglePolicy::GetAllPolicies()) diff --git a/src/AppInstallerCLITests/InstallFlow.cpp b/src/AppInstallerCLITests/InstallFlow.cpp index 56f117bceb..a52dd702a1 100644 --- a/src/AppInstallerCLITests/InstallFlow.cpp +++ b/src/AppInstallerCLITests/InstallFlow.cpp @@ -450,7 +450,7 @@ TEST_CASE("InstallFlow_Zip_ArchiveScanOverride_AdminSettingDisabled", "[InstallF context.Args.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_Zip_Exe.yaml").GetPath().u8string()); context.Args.AddArg(Execution::Args::Type::IgnoreLocalArchiveMalwareScan); - DisableAdminSetting(AppInstaller::Settings::AdminSetting::LocalArchiveMalwareScanOverride); + DisableAdminSetting(AppInstaller::Settings::BoolAdminSetting::LocalArchiveMalwareScanOverride); TestHook::SetScanArchiveResult_Override scanArchiveResultOverride(false); @@ -478,7 +478,7 @@ TEST_CASE("InstallFlow_Zip_ArchiveScanOverride_AdminSettingEnabled", "[InstallFl context.Args.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_Zip_Exe.yaml").GetPath().u8string()); context.Args.AddArg(Execution::Args::Type::IgnoreLocalArchiveMalwareScan); - EnableAdminSetting(AppInstaller::Settings::AdminSetting::LocalArchiveMalwareScanOverride); + EnableAdminSetting(AppInstaller::Settings::BoolAdminSetting::LocalArchiveMalwareScanOverride); TestHook::SetScanArchiveResult_Override scanArchiveResultOverride(false); diff --git a/src/AppInstallerCLITests/RestClient.cpp b/src/AppInstallerCLITests/RestClient.cpp index 00af2e2a27..d7ad277a73 100644 --- a/src/AppInstallerCLITests/RestClient.cpp +++ b/src/AppInstallerCLITests/RestClient.cpp @@ -47,11 +47,11 @@ TEST_CASE("GetSupportedInterface", "[RestSource]") IRestClient::Information info{ "TestId", { "1.0.0" } }; Version version{ "1.0.0" }; - REQUIRE(RestClient::GetSupportedInterface(TestRestUri, {}, info, {}, version)->GetVersion() == version); + REQUIRE(RestClient::GetSupportedInterface(TestRestUri, {}, info, {}, version, {})->GetVersion() == version); // Update this test to next version so that we don't forget to add to supported versions before rest e2e tests are available. Version invalid{ "1.8.0" }; - REQUIRE_THROWS_HR(RestClient::GetSupportedInterface(TestRestUri, {}, info, {}, invalid), APPINSTALLER_CLI_ERROR_RESTSOURCE_INVALID_VERSION); + REQUIRE_THROWS_HR(RestClient::GetSupportedInterface(TestRestUri, {}, info, {}, invalid, {}), APPINSTALLER_CLI_ERROR_RESTSOURCE_INVALID_VERSION); Authentication::AuthenticationArguments authArgs; authArgs.Mode = Authentication::AuthenticationMode::Silent; @@ -60,12 +60,12 @@ TEST_CASE("GetSupportedInterface", "[RestSource]") // GetSupportedInterface throws on unknown authentication type. IRestClient::Information infoWithUnknownAuthenticationType{ "TestId", { "1.7.0" } }; infoWithUnknownAuthenticationType.Authentication.Type = Authentication::AuthenticationType::Unknown; - REQUIRE_THROWS_HR(RestClient::GetSupportedInterface(TestRestUri, {}, infoWithUnknownAuthenticationType, authArgs, version_1_7), APPINSTALLER_CLI_ERROR_AUTHENTICATION_TYPE_NOT_SUPPORTED); + REQUIRE_THROWS_HR(RestClient::GetSupportedInterface(TestRestUri, {}, infoWithUnknownAuthenticationType, authArgs, version_1_7, {}), APPINSTALLER_CLI_ERROR_AUTHENTICATION_TYPE_NOT_SUPPORTED); // GetSupportedInterface throws on invalid authentication info. IRestClient::Information infoWithInvalidAuthenticationInfo{ "TestId", { "1.7.0" } }; infoWithInvalidAuthenticationInfo.Authentication.Type = Authentication::AuthenticationType::MicrosoftEntraId; - REQUIRE_THROWS_HR(RestClient::GetSupportedInterface(TestRestUri, {}, infoWithInvalidAuthenticationInfo, authArgs, version_1_7), APPINSTALLER_CLI_ERROR_INVALID_AUTHENTICATION_INFO); + REQUIRE_THROWS_HR(RestClient::GetSupportedInterface(TestRestUri, {}, infoWithInvalidAuthenticationInfo, authArgs, version_1_7, {}), APPINSTALLER_CLI_ERROR_INVALID_AUTHENTICATION_INFO); } TEST_CASE("GetInformation_Success", "[RestSource]") @@ -277,7 +277,7 @@ TEST_CASE("RestClientCreate_UnsupportedVersion", "[RestSource]") }})delimiter"); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, sample) }; - REQUIRE_THROWS_HR(RestClient::Create("https://restsource.com/api", {}, {}, {}, std::move(helper)), APPINSTALLER_CLI_ERROR_UNSUPPORTED_RESTSOURCE); + REQUIRE_THROWS_HR(RestClient::Create("https://restsource.com/api", {}, {}, std::move(helper)), APPINSTALLER_CLI_ERROR_UNSUPPORTED_RESTSOURCE); } TEST_CASE("RestClientCreate_UnsupportedAuthenticationMethod", "[RestSource]") @@ -297,7 +297,7 @@ TEST_CASE("RestClientCreate_UnsupportedAuthenticationMethod", "[RestSource]") HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, sample) }; Authentication::AuthenticationArguments authArgs; authArgs.Mode = Authentication::AuthenticationMode::Silent; - REQUIRE_THROWS_HR(RestClient::Create("https://restsource.com/api", {}, {}, std::move(authArgs), std::move(helper)), APPINSTALLER_CLI_ERROR_AUTHENTICATION_TYPE_NOT_SUPPORTED); + REQUIRE_THROWS_HR(RestClient::Create("https://restsource.com/api", {}, {}, std::move(helper), std::move(authArgs)), APPINSTALLER_CLI_ERROR_AUTHENTICATION_TYPE_NOT_SUPPORTED); } TEST_CASE("RestClientCreate_InvalidAuthenticationArguments", "[RestSource]") @@ -320,7 +320,7 @@ TEST_CASE("RestClientCreate_InvalidAuthenticationArguments", "[RestSource]") HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, sample) }; Authentication::AuthenticationArguments authArgs; authArgs.Mode = Authentication::AuthenticationMode::Unknown; - REQUIRE_THROWS_HR(RestClient::Create("https://restsource.com/api", {}, {}, std::move(authArgs), std::move(helper)), E_UNEXPECTED); + REQUIRE_THROWS_HR(RestClient::Create("https://restsource.com/api", {}, {}, std::move(helper), std::move(authArgs)), E_UNEXPECTED); } TEST_CASE("RestClientCreate_1.0_Success", "[RestSource]") @@ -335,7 +335,7 @@ TEST_CASE("RestClientCreate_1.0_Success", "[RestSource]") }})delimiter"); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, sample) }; - RestClient client = RestClient::Create(TestRestUri, {}, {}, {}, std::move(helper)); + RestClient client = RestClient::Create(TestRestUri, {}, {}, std::move(helper), {}); REQUIRE(client.GetSourceIdentifier() == "Source123"); } @@ -372,7 +372,7 @@ TEST_CASE("RestClientCreate_1.1_Success", "[RestSource]") }})delimiter"); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, sample) }; - RestClient client = RestClient::Create(TestRestUri, {}, {}, {}, std::move(helper)); + RestClient client = RestClient::Create(TestRestUri, {}, {}, std::move(helper)); REQUIRE(client.GetSourceIdentifier() == "Source123"); auto information = client.GetSourceInformation(); REQUIRE(information.SourceAgreementsIdentifier == "agreementV1"); @@ -438,7 +438,7 @@ TEST_CASE("RestClientCreate_1.7_Success", "[RestSource]") Authentication::AuthenticationArguments authArgs; authArgs.Mode = Authentication::AuthenticationMode::Silent; HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, sample) }; - RestClient client = RestClient::Create(TestRestUri, {}, {}, std::move(authArgs), std::move(helper)); + RestClient client = RestClient::Create(TestRestUri, {}, {}, std::move(helper), std::move(authArgs)); REQUIRE(client.GetSourceIdentifier() == "Source123"); auto information = client.GetSourceInformation(); REQUIRE(information.SourceAgreementsIdentifier == "agreementV1"); diff --git a/src/AppInstallerCLITests/RestInterface_1_1.cpp b/src/AppInstallerCLITests/RestInterface_1_1.cpp index a167c03427..3334388146 100644 --- a/src/AppInstallerCLITests/RestInterface_1_1.cpp +++ b/src/AppInstallerCLITests/RestInterface_1_1.cpp @@ -310,7 +310,7 @@ TEST_CASE("Search_BadResponse_UnsupportedPackageMatchFields", "[RestSource][Inte })delimiter"); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; - Interface v1_1{ TestRestUriString, GetTestSourceInformation(), {}, std::move(helper) }; + Interface v1_1{ TestRestUriString, std::move(helper), GetTestSourceInformation(), {} }; AppInstaller::Repository::SearchRequest request; PackageMatchFilter filter{ PackageMatchField::Name, MatchType::Exact, "Foo" }; request.Filters.emplace_back(std::move(filter)); @@ -326,7 +326,7 @@ TEST_CASE("Search_BadResponse_RequiredPackageMatchFields", "[RestSource][Interfa })delimiter"); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; - Interface v1_1{ TestRestUriString, GetTestSourceInformation(), {}, std::move(helper) }; + Interface v1_1{ TestRestUriString, std::move(helper), GetTestSourceInformation(), {} }; AppInstaller::Repository::SearchRequest request; PackageMatchFilter filter{ PackageMatchField::Name, MatchType::Exact, "Foo" }; request.Filters.emplace_back(std::move(filter)); @@ -342,7 +342,7 @@ TEST_CASE("GetManifests_BadResponse_UnsupportedQueryParameters", "[RestSource][I })delimiter"); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; - Interface v1_1{ TestRestUriString, GetTestSourceInformation(), {}, std::move(helper) }; + Interface v1_1{ TestRestUriString, std::move(helper), GetTestSourceInformation(), {} }; REQUIRE_THROWS_HR(v1_1.GetManifests("Foo"), APPINSTALLER_CLI_ERROR_UNSUPPORTED_SOURCE_REQUEST); } @@ -355,7 +355,7 @@ TEST_CASE("GetManifests_BadResponse_RequiredQueryParameters", "[RestSource][Inte })delimiter"); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; - Interface v1_1{ TestRestUriString, GetTestSourceInformation(), {}, std::move(helper) }; + Interface v1_1{ TestRestUriString, std::move(helper), GetTestSourceInformation(), {} }; REQUIRE_THROWS_HR(v1_1.GetManifests("Foo"), APPINSTALLER_CLI_ERROR_UNSUPPORTED_SOURCE_REQUEST); } @@ -375,7 +375,7 @@ TEST_CASE("Search_BadRequest_UnsupportedPackageMatchFields", "[RestSource][Inter })delimiter"); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; - Interface v1_1{ TestRestUriString, GetTestSourceInformation(), {}, std::move(helper) }; + Interface v1_1{ TestRestUriString, std::move(helper), GetTestSourceInformation(), {} }; AppInstaller::Repository::SearchRequest request; PackageMatchFilter filter{ PackageMatchField::Moniker, MatchType::Exact, "Foo" }; request.Filters.emplace_back(std::move(filter)); @@ -398,7 +398,7 @@ TEST_CASE("Search_GoodRequest_OnlyMarketRequired", "[RestSource][Interface_1_1]" })delimiter"); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; - Interface v1_1{ TestRestUriString, GetTestSourceInformation(), {}, std::move(helper) }; + Interface v1_1{ TestRestUriString, std::move(helper), GetTestSourceInformation(), {} }; AppInstaller::Repository::SearchRequest request; PackageMatchFilter filter{ PackageMatchField::Name, MatchType::Exact, "Foo" }; request.Filters.emplace_back(std::move(filter)); @@ -443,7 +443,7 @@ TEST_CASE("GetManifests_BadRequest_UnsupportedQueryParameters", "[RestSource][In })delimiter"); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; - Interface v1_1{ TestRestUriString, GetTestSourceInformation(), {}, std::move(helper) }; + Interface v1_1{ TestRestUriString, std::move(helper), GetTestSourceInformation(), {} }; REQUIRE_THROWS_HR(v1_1.GetManifestByVersion("Foo", "1.0", "beta"), APPINSTALLER_CLI_ERROR_UNSUPPORTED_SOURCE_REQUEST); } @@ -479,7 +479,7 @@ TEST_CASE("GetManifests_GoodRequest_OnlyMarketRequired", "[RestSource][Interface IRestClient::Information info = GetTestSourceInformation(); info.UnsupportedQueryParameters.clear(); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; - Interface v1_1{ TestRestUriString, info, {}, std::move(helper) }; + Interface v1_1{ TestRestUriString, std::move(helper), info, {} }; auto manifestResult = v1_1.GetManifestByVersion("Foo", "5.0.0", ""); REQUIRE(manifestResult.has_value()); const Manifest& manifest = manifestResult.value(); @@ -526,7 +526,7 @@ TEST_CASE("GetManifests_GoodResponse_MSStoreType", "[RestSource][Interface_1_1]" })delimiter"); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(msstoreInstallerResponse)) }; - Interface v1_1{ TestRestUriString, GetTestSourceInformation(), {}, std::move(helper) }; + Interface v1_1{ TestRestUriString, std::move(helper), GetTestSourceInformation(), {} }; std::vector manifests = v1_1.GetManifests("Foo.Bar"); REQUIRE(manifests.size() == 1); @@ -542,7 +542,7 @@ TEST_CASE("GetManifests_GoodResponse_V1_1", "[RestSource][Interface_1_1]") GoodManifest_AllFields sampleManifest; utility::string_t sample = sampleManifest.GetSampleManifest_AllFields(); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; - Interface v1_1{ TestRestUriString, {}, {}, std::move(helper) }; + Interface v1_1{ TestRestUriString, std::move(helper), {} }; std::vector manifests = v1_1.GetManifests("Foo.Bar"); REQUIRE(manifests.size() == 1); diff --git a/src/AppInstallerCLITests/RestInterface_1_4.cpp b/src/AppInstallerCLITests/RestInterface_1_4.cpp index a1c3bb7add..e136070c42 100644 --- a/src/AppInstallerCLITests/RestInterface_1_4.cpp +++ b/src/AppInstallerCLITests/RestInterface_1_4.cpp @@ -361,7 +361,7 @@ TEST_CASE("GetManifests_GoodResponse_V1_4", "[RestSource][Interface_1_4]") GoodManifest_AllFields sampleManifest; utility::string_t sample = sampleManifest.GetSampleManifest_AllFields(); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; - Interface v1_4{ TestRestUriString, {}, {}, std::move(helper) }; + Interface v1_4{ TestRestUriString, std::move(helper), {} }; std::vector manifests = v1_4.GetManifests("Foo.Bar"); REQUIRE(manifests.size() == 1); @@ -404,7 +404,7 @@ TEST_CASE("Search_GoodResponse_V1_4", "[RestSource][Interface_1_4]") })delimiter"); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; - Interface v1_4{ TestRestUriString, {}, {}, std::move(helper) }; + Interface v1_4{ TestRestUriString, std::move(helper), {} }; Schema::IRestClient::SearchResult searchResponse = v1_4.Search({}); REQUIRE(searchResponse.Matches.size() == 1); Schema::IRestClient::Package package = searchResponse.Matches.at(0); diff --git a/src/AppInstallerCLITests/RestInterface_1_5.cpp b/src/AppInstallerCLITests/RestInterface_1_5.cpp index 69416b2c2e..c1a04dc60d 100644 --- a/src/AppInstallerCLITests/RestInterface_1_5.cpp +++ b/src/AppInstallerCLITests/RestInterface_1_5.cpp @@ -387,7 +387,7 @@ TEST_CASE("GetManifests_GoodResponse_V1_5", "[RestSource][Interface_1_5]") GoodManifest_AllFields sampleManifest; utility::string_t sample = sampleManifest.GetSampleManifest_AllFields(); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; - Interface v1_5{ TestRestUriString, {}, {}, std::move(helper) }; + Interface v1_5{ TestRestUriString, std::move(helper), {} }; std::vector manifests = v1_5.GetManifests("Foo.Bar"); REQUIRE(manifests.size() == 1); diff --git a/src/AppInstallerCLITests/RestInterface_1_6.cpp b/src/AppInstallerCLITests/RestInterface_1_6.cpp index 0cddd5970c..da1582b69c 100644 --- a/src/AppInstallerCLITests/RestInterface_1_6.cpp +++ b/src/AppInstallerCLITests/RestInterface_1_6.cpp @@ -389,7 +389,7 @@ TEST_CASE("GetManifests_GoodResponse_V1_6", "[RestSource][Interface_1_6]") GoodManifest_AllFields sampleManifest; utility::string_t sample = sampleManifest.GetSampleManifest_AllFields(); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; - Interface v1_6{ TestRestUriString, {}, {}, std::move(helper) }; + Interface v1_6{ TestRestUriString, std::move(helper), {} }; std::vector manifests = v1_6.GetManifests("Foo.Bar"); REQUIRE(manifests.size() == 1); diff --git a/src/AppInstallerCLITests/RestInterface_1_7.cpp b/src/AppInstallerCLITests/RestInterface_1_7.cpp index e2ca66d9e9..bde849b644 100644 --- a/src/AppInstallerCLITests/RestInterface_1_7.cpp +++ b/src/AppInstallerCLITests/RestInterface_1_7.cpp @@ -457,7 +457,7 @@ TEST_CASE("GetManifests_GoodRequest_Authentication", "[RestSource][Interface_1_7 // GetManifest should succeed with expected value. HttpClientHelper helper{ GetHeaderVerificationHandler(web::http::status_codes::OK, SampleGetManifestResponse, { web::http::header_names::authorization, JSON::GetUtilityString(CreateBearerToken(expectedToken)) }, web::http::status_codes::Unauthorized) }; - Interface v1_7{ TestRestUriString, GetTestSourceInformation(), {}, GetTestAuthenticationArguments(), std::move(helper) }; + Interface v1_7{ TestRestUriString, std::move(helper), GetTestSourceInformation(), {}, GetTestAuthenticationArguments() }; auto manifestResult = v1_7.GetManifestByVersion("Foo.Bar", "5.0.0", ""); REQUIRE(manifestResult.has_value()); const auto& manifest = manifestResult.value(); @@ -482,7 +482,7 @@ TEST_CASE("GetManifests_BadRequest_AuthenticationFailed", "[RestSource][Interfac // GetManifest should fail with authentication failure HttpClientHelper helper{ GetHeaderVerificationHandler(web::http::status_codes::OK, SampleGetManifestResponse, { web::http::header_names::authorization, JSON::GetUtilityString(CreateBearerToken(expectedToken)) }, web::http::status_codes::Unauthorized) }; - Interface v1_7{ TestRestUriString, GetTestSourceInformation(), {}, GetTestAuthenticationArguments(), std::move(helper) }; + Interface v1_7{ TestRestUriString, std::move(helper), GetTestSourceInformation(), {}, GetTestAuthenticationArguments() }; REQUIRE_THROWS_HR(v1_7.GetManifestByVersion("Foo.Bar", "5.0.0", ""), APPINSTALLER_CLI_ERROR_AUTHENTICATION_FAILED); } @@ -504,7 +504,7 @@ TEST_CASE("GetManifests_BadRequest_InvalidAuthenticationToken", "[RestSource][In // GetManifest should fail with access denied HttpClientHelper helper{ GetHeaderVerificationHandler(web::http::status_codes::OK, SampleGetManifestResponse, { web::http::header_names::authorization, JSON::GetUtilityString(CreateBearerToken(expectedToken)) }, web::http::status_codes::Unauthorized) }; - Interface v1_7{ TestRestUriString, GetTestSourceInformation(), {}, GetTestAuthenticationArguments(), std::move(helper) }; + Interface v1_7{ TestRestUriString, std::move(helper), GetTestSourceInformation(), {}, GetTestAuthenticationArguments() }; REQUIRE_THROWS_HR(v1_7.GetManifestByVersion("Foo.Bar", "5.0.0", ""), HTTP_E_STATUS_DENIED); } @@ -526,7 +526,7 @@ TEST_CASE("Search_GoodRequest_Authentication", "[RestSource][Interface_1_7]") // Search should succeed with expected value. HttpClientHelper helper{ GetHeaderVerificationHandler(web::http::status_codes::OK, SampleSearchResponse, { web::http::header_names::authorization, JSON::GetUtilityString(CreateBearerToken(expectedToken)) }, web::http::status_codes::Unauthorized) }; - Interface v1_7{ TestRestUriString, GetTestSourceInformation(), {}, GetTestAuthenticationArguments(), std::move(helper) }; + Interface v1_7{ TestRestUriString, std::move(helper), GetTestSourceInformation(), {}, GetTestAuthenticationArguments() }; SearchRequest request; PackageMatchFilter filter{ PackageMatchField::Name, MatchType::Exact, "package" }; request.Filters.emplace_back(std::move(filter)); @@ -553,7 +553,7 @@ TEST_CASE("Search_BadRequest_AuthenticationFailed", "[RestSource][Interface_1_7] // Search should fail with authentication failure HttpClientHelper helper{ GetHeaderVerificationHandler(web::http::status_codes::OK, SampleSearchResponse, { web::http::header_names::authorization, JSON::GetUtilityString(CreateBearerToken(expectedToken)) }, web::http::status_codes::Unauthorized) }; - Interface v1_7{ TestRestUriString, GetTestSourceInformation(), {}, GetTestAuthenticationArguments(), std::move(helper) }; + Interface v1_7{ TestRestUriString, std::move(helper), GetTestSourceInformation(), {}, GetTestAuthenticationArguments() }; SearchRequest request; PackageMatchFilter filter{ PackageMatchField::Name, MatchType::Exact, "package" }; request.Filters.emplace_back(std::move(filter)); @@ -578,7 +578,7 @@ TEST_CASE("Search_BadRequest_InvalidAuthenticationToken", "[RestSource][Interfac // Search should fail with access denied HttpClientHelper helper{ GetHeaderVerificationHandler(web::http::status_codes::OK, SampleSearchResponse, { web::http::header_names::authorization, JSON::GetUtilityString(CreateBearerToken(expectedToken)) }, web::http::status_codes::Unauthorized) }; - Interface v1_7{ TestRestUriString, GetTestSourceInformation(), {}, GetTestAuthenticationArguments(), std::move(helper) }; + Interface v1_7{ TestRestUriString, std::move(helper), GetTestSourceInformation(), {}, GetTestAuthenticationArguments() }; SearchRequest request; PackageMatchFilter filter{ PackageMatchField::Name, MatchType::Exact, "package" }; request.Filters.emplace_back(std::move(filter)); @@ -590,7 +590,7 @@ TEST_CASE("GetManifests_GoodResponse_V1_7", "[RestSource][Interface_1_7]") GoodManifest_AllFields sampleManifest; utility::string_t sample = sampleManifest.GetSampleManifest_AllFields(); HttpClientHelper helper{ GetTestRestRequestHandler(web::http::status_codes::OK, std::move(sample)) }; - Interface v1_7{ TestRestUriString, {}, {}, {}, std::move(helper) }; + Interface v1_7{ TestRestUriString, std::move(helper), {} }; std::vector manifests = v1_7.GetManifests("Foo.Bar"); REQUIRE(manifests.size() == 1); diff --git a/src/AppInstallerCLITests/TestSettings.h b/src/AppInstallerCLITests/TestSettings.h index 878264a8c1..7da1a728ef 100644 --- a/src/AppInstallerCLITests/TestSettings.h +++ b/src/AppInstallerCLITests/TestSettings.h @@ -22,6 +22,7 @@ namespace TestCommon const std::wstring BypassCertificatePinningForMicrosoftStoreValueName = L"EnableBypassCertificatePinningForMicrosoftStore"; const std::wstring EnableWindowsPackageManagerCommandLineInterfaces = L"EnableWindowsPackageManagerCommandLineInterfaces"; const std::wstring ConfigurationPolicyValueName = L"EnableWindowsPackageManagerConfiguration"; + const std::wstring ProxyCommandLineOptionsPolicyValueName = L"EnableWindowsPackageManagerProxyCommandLineOptions"; const std::wstring SourceUpdateIntervalPolicyValueName = L"SourceAutoUpdateInterval"; const std::wstring SourceUpdateIntervalPolicyOldValueName = L"SourceAutoUpdateIntervalInMinutes"; diff --git a/src/AppInstallerCLITests/pch.h b/src/AppInstallerCLITests/pch.h index fdceff3fea..12cd316374 100644 --- a/src/AppInstallerCLITests/pch.h +++ b/src/AppInstallerCLITests/pch.h @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include diff --git a/src/AppInstallerCommonCore/AdminSettings.cpp b/src/AppInstallerCommonCore/AdminSettings.cpp index 71d0f7ba3b..89a23d64ea 100644 --- a/src/AppInstallerCommonCore/AdminSettings.cpp +++ b/src/AppInstallerCommonCore/AdminSettings.cpp @@ -19,6 +19,9 @@ namespace AppInstaller::Settings constexpr Utility::LocIndView s_AdminSettingsYaml_BypassCertificatePinningForMicrosoftStore = "BypassCertificatePinningForMicrosoftStore"_liv; constexpr Utility::LocIndView s_AdminSettingsYaml_InstallerHashOverride = "InstallerHashOverride"_liv; constexpr Utility::LocIndView s_AdminSettingsYaml_LocalArchiveMalwareScanOverride = "LocalArchiveMalwareScanOverride"_liv; + constexpr Utility::LocIndView s_AdminSettingsYaml_ProxyCommandLineOptions = "ProxyCommandLineOptions"_liv; + + constexpr Utility::LocIndView s_AdminSettingsYaml_DefaultProxy = "DefaultProxy"_liv; // Attempts to read a single scalar value from the node. template @@ -42,20 +45,30 @@ namespace AppInstaller::Settings bool BypassCertificatePinningForMicrosoftStore = false; bool InstallerHashOverride = false; bool LocalArchiveMalwareScanOverride = false; + bool ProxyCommandLineOptions = false; + + std::optional DefaultProxy; }; struct AdminSettingsInternal { AdminSettingsInternal(); - void SetAdminSetting(AdminSetting setting, bool enabled); + void SetAdminSetting(BoolAdminSetting setting, bool enabled); + void SetAdminSetting(StringAdminSetting setting, const std::optional& value); - bool GetAdminSettingBoolValue(AdminSetting setting) const; + bool GetAdminSettingValue(BoolAdminSetting setting) const; + std::optional GetAdminSettingValue(StringAdminSetting setting) const; private: void LoadAdminSettings(); [[nodiscard]] bool SaveAdminSettings(); + // Sets the value of an admin setting using the given function and then saves the changes. + // Encapsulates the retry and reload logic. + // Stops if the value cannot be set, as indicated by the return value of setValue() + void SetAdminSettingAndSave(std::function setValue); + Stream m_settingStream; AdminSettingValues m_settingValues; }; @@ -65,25 +78,12 @@ namespace AppInstaller::Settings LoadAdminSettings(); } - void AdminSettingsInternal::SetAdminSetting(AdminSetting setting, bool enabled) + void AdminSettingsInternal::SetAdminSettingAndSave(std::function setValue) { for (size_t i = 0; i < 10; ++i) { - switch (setting) + if (!setValue()) { - case AdminSetting::LocalManifestFiles: - m_settingValues.LocalManifestFiles = enabled; - break; - case AdminSetting::BypassCertificatePinningForMicrosoftStore: - m_settingValues.BypassCertificatePinningForMicrosoftStore = enabled; - break; - case AdminSetting::InstallerHashOverride: - m_settingValues.InstallerHashOverride = enabled; - break; - case AdminSetting::LocalArchiveMalwareScanOverride: - m_settingValues.LocalArchiveMalwareScanOverride = enabled; - break; - default: return; } @@ -99,23 +99,78 @@ namespace AppInstaller::Settings THROW_HR_MSG(E_UNEXPECTED, "Too many attempts at SaveAdminSettings"); } - bool AdminSettingsInternal::GetAdminSettingBoolValue(AdminSetting setting) const + void AdminSettingsInternal::SetAdminSetting(BoolAdminSetting setting, bool enabled) + { + SetAdminSettingAndSave([&]() + { + switch (setting) + { + case BoolAdminSetting::LocalManifestFiles: + m_settingValues.LocalManifestFiles = enabled; + return true; + case BoolAdminSetting::BypassCertificatePinningForMicrosoftStore: + m_settingValues.BypassCertificatePinningForMicrosoftStore = enabled; + return true; + case BoolAdminSetting::InstallerHashOverride: + m_settingValues.InstallerHashOverride = enabled; + return true; + case BoolAdminSetting::LocalArchiveMalwareScanOverride: + m_settingValues.LocalArchiveMalwareScanOverride = enabled; + return true; + case BoolAdminSetting::ProxyCommandLineOptions: + m_settingValues.ProxyCommandLineOptions = enabled; + return true; + default: + return false; + } + }); + } + + void AdminSettingsInternal::SetAdminSetting(StringAdminSetting setting, const std::optional& value) + { + SetAdminSettingAndSave([&]() + { + switch (setting) + { + case StringAdminSetting::DefaultProxy: + m_settingValues.DefaultProxy = value; + return true; + default: + return false; + } + }); + } + + bool AdminSettingsInternal::GetAdminSettingValue(BoolAdminSetting setting) const { switch (setting) { - case AdminSetting::LocalManifestFiles: + case BoolAdminSetting::LocalManifestFiles: return m_settingValues.LocalManifestFiles; - case AdminSetting::BypassCertificatePinningForMicrosoftStore: + case BoolAdminSetting::BypassCertificatePinningForMicrosoftStore: return m_settingValues.BypassCertificatePinningForMicrosoftStore; - case AdminSetting::InstallerHashOverride: + case BoolAdminSetting::InstallerHashOverride: return m_settingValues.InstallerHashOverride; - case AdminSetting::LocalArchiveMalwareScanOverride: + case BoolAdminSetting::LocalArchiveMalwareScanOverride: return m_settingValues.LocalArchiveMalwareScanOverride; + case BoolAdminSetting::ProxyCommandLineOptions: + return m_settingValues.ProxyCommandLineOptions; default: return false; } } + std::optional AdminSettingsInternal::GetAdminSettingValue(StringAdminSetting setting) const + { + switch (setting) + { + case StringAdminSetting::DefaultProxy: + return m_settingValues.DefaultProxy; + default: + return std::nullopt; + } + } + void AdminSettingsInternal::LoadAdminSettings() { auto stream = m_settingStream.Get(); @@ -154,6 +209,13 @@ namespace AppInstaller::Settings TryReadScalar(document, s_AdminSettingsYaml_BypassCertificatePinningForMicrosoftStore, m_settingValues.BypassCertificatePinningForMicrosoftStore); TryReadScalar(document, s_AdminSettingsYaml_InstallerHashOverride, m_settingValues.InstallerHashOverride); TryReadScalar(document, s_AdminSettingsYaml_LocalArchiveMalwareScanOverride, m_settingValues.LocalArchiveMalwareScanOverride); + TryReadScalar(document, s_AdminSettingsYaml_ProxyCommandLineOptions, m_settingValues.ProxyCommandLineOptions); + + std::string defaultProxy; + if (TryReadScalar(document, s_AdminSettingsYaml_DefaultProxy, defaultProxy)) + { + m_settingValues.DefaultProxy.emplace(std::move(defaultProxy)); + } } bool AdminSettingsInternal::SaveAdminSettings() @@ -164,74 +226,128 @@ namespace AppInstaller::Settings out << YAML::Key << s_AdminSettingsYaml_BypassCertificatePinningForMicrosoftStore << YAML::Value << m_settingValues.BypassCertificatePinningForMicrosoftStore; out << YAML::Key << s_AdminSettingsYaml_InstallerHashOverride << YAML::Value << m_settingValues.InstallerHashOverride; out << YAML::Key << s_AdminSettingsYaml_LocalArchiveMalwareScanOverride << YAML::Value << m_settingValues.LocalArchiveMalwareScanOverride; + out << YAML::Key << s_AdminSettingsYaml_ProxyCommandLineOptions << YAML::Value << m_settingValues.ProxyCommandLineOptions; + + if (m_settingValues.DefaultProxy) + { + out << YAML::Key << s_AdminSettingsYaml_DefaultProxy << YAML::Value << m_settingValues.DefaultProxy.value(); + } + out << YAML::EndMap; return m_settingStream.Set(out.str()); } + + auto GetPolicyStateForSetting(BoolAdminSetting setting) + { + auto policy = GetAdminSettingPolicy(setting); + return GroupPolicies().GetState(policy); + } + + std::optional> GetPolicyStateForSetting(StringAdminSetting setting) + { + switch (setting) + { + case AppInstaller::Settings::StringAdminSetting::DefaultProxy: + return GroupPolicies().GetValueRef(); + default: + return std::nullopt; + } + } } - AdminSetting StringToAdminSetting(std::string_view in) + BoolAdminSetting StringToBoolAdminSetting(std::string_view in) { - AdminSetting result = AdminSetting::Unknown; + BoolAdminSetting result = BoolAdminSetting::Unknown; if (Utility::CaseInsensitiveEquals(s_AdminSettingsYaml_LocalManifestFiles, in)) { - result = AdminSetting::LocalManifestFiles; + result = BoolAdminSetting::LocalManifestFiles; } else if (Utility::CaseInsensitiveEquals(s_AdminSettingsYaml_BypassCertificatePinningForMicrosoftStore, in)) { - result = AdminSetting::BypassCertificatePinningForMicrosoftStore; + result = BoolAdminSetting::BypassCertificatePinningForMicrosoftStore; } else if (Utility::CaseInsensitiveEquals(s_AdminSettingsYaml_InstallerHashOverride, in)) { - result = AdminSetting::InstallerHashOverride; + result = BoolAdminSetting::InstallerHashOverride; } else if (Utility::CaseInsensitiveEquals(s_AdminSettingsYaml_LocalArchiveMalwareScanOverride, in)) { - result = AdminSetting::LocalArchiveMalwareScanOverride; + result = BoolAdminSetting::LocalArchiveMalwareScanOverride; + } + else if (Utility::CaseInsensitiveEquals(s_AdminSettingsYaml_ProxyCommandLineOptions, in)) + { + result = BoolAdminSetting::ProxyCommandLineOptions; + } + + return result; + } + + StringAdminSetting StringToStringAdminSetting(std::string_view in) + { + StringAdminSetting result = StringAdminSetting::Unknown; + + if (Utility::CaseInsensitiveEquals(s_AdminSettingsYaml_DefaultProxy, in)) + { + result = StringAdminSetting::DefaultProxy; } return result; } - Utility::LocIndView AdminSettingToString(AdminSetting setting) + Utility::LocIndView AdminSettingToString(BoolAdminSetting setting) { switch (setting) { - case AdminSetting::LocalManifestFiles: + case BoolAdminSetting::LocalManifestFiles: return s_AdminSettingsYaml_LocalManifestFiles; - case AdminSetting::BypassCertificatePinningForMicrosoftStore: + case BoolAdminSetting::BypassCertificatePinningForMicrosoftStore: return s_AdminSettingsYaml_BypassCertificatePinningForMicrosoftStore; - case AdminSetting::InstallerHashOverride: + case BoolAdminSetting::InstallerHashOverride: return s_AdminSettingsYaml_InstallerHashOverride; - case AdminSetting::LocalArchiveMalwareScanOverride: + case BoolAdminSetting::LocalArchiveMalwareScanOverride: return s_AdminSettingsYaml_LocalArchiveMalwareScanOverride; + case BoolAdminSetting::ProxyCommandLineOptions: + return s_AdminSettingsYaml_ProxyCommandLineOptions; + default: + return "Unknown"_liv; + } + } + + Utility::LocIndView AdminSettingToString(StringAdminSetting setting) + { + switch (setting) + { + case StringAdminSetting::DefaultProxy: + return s_AdminSettingsYaml_DefaultProxy; default: return "Unknown"_liv; } } - TogglePolicy::Policy GetAdminSettingPolicy(AdminSetting setting) + TogglePolicy::Policy GetAdminSettingPolicy(BoolAdminSetting setting) { switch (setting) { - case AdminSetting::LocalManifestFiles: + case BoolAdminSetting::LocalManifestFiles: return TogglePolicy::Policy::LocalManifestFiles; - case AdminSetting::BypassCertificatePinningForMicrosoftStore: + case BoolAdminSetting::BypassCertificatePinningForMicrosoftStore: return TogglePolicy::Policy::BypassCertificatePinningForMicrosoftStore; - case AdminSetting::InstallerHashOverride: + case BoolAdminSetting::InstallerHashOverride: return TogglePolicy::Policy::HashOverride; - case AdminSetting::LocalArchiveMalwareScanOverride: + case BoolAdminSetting::LocalArchiveMalwareScanOverride: return TogglePolicy::Policy::LocalArchiveMalwareScanOverride; + case BoolAdminSetting::ProxyCommandLineOptions: + return TogglePolicy::Policy::ProxyCommandLineOptions; default: return TogglePolicy::Policy::None; } } - bool EnableAdminSetting(AdminSetting setting) + bool EnableAdminSetting(BoolAdminSetting setting) { - auto policy = GetAdminSettingPolicy(setting); - if (GroupPolicies().GetState(policy) == PolicyState::Disabled) + if (GetPolicyStateForSetting(setting) == PolicyState::Disabled) { return false; } @@ -241,10 +357,9 @@ namespace AppInstaller::Settings return true; } - bool DisableAdminSetting(AdminSetting setting) + bool DisableAdminSetting(BoolAdminSetting setting) { - auto policy = GetAdminSettingPolicy(setting); - if (GroupPolicies().GetState(policy) == PolicyState::Enabled) + if (GetPolicyStateForSetting(setting) == PolicyState::Enabled) { return false; } @@ -254,31 +369,64 @@ namespace AppInstaller::Settings return true; } - bool IsAdminSettingEnabled(AdminSetting setting) + bool IsAdminSettingEnabled(BoolAdminSetting setting) { // Check for a policy that overrides this setting. - auto policy = GetAdminSettingPolicy(setting); - auto policyState = GroupPolicies().GetState(policy); + auto policyState = GetPolicyStateForSetting(setting); if (policyState != PolicyState::NotConfigured) { return policyState == PolicyState::Enabled; } AdminSettingsInternal adminSettingsInternal; - return adminSettingsInternal.GetAdminSettingBoolValue(setting); + return adminSettingsInternal.GetAdminSettingValue(setting); + } + + bool SetAdminSetting(StringAdminSetting setting, std::string_view value) + { + if (GetPolicyStateForSetting(setting)) + { + return false; + } + + AdminSettingsInternal adminSettingsInternal; + adminSettingsInternal.SetAdminSetting(setting, std::string{ value }); + return true; } - std::vector GetAllAdminSettings() + bool ResetAdminSetting(StringAdminSetting setting) { - std::vector result; - using AdminSetting_t = std::underlying_type_t; + if (GetPolicyStateForSetting(setting)) + { + return false; + } - // Skip Unknown. - for (AdminSetting_t i = 1 + static_cast(AdminSetting::Unknown); i < static_cast(AdminSetting::Max); ++i) + AdminSettingsInternal adminSettingsInternal; + adminSettingsInternal.SetAdminSetting(setting, std::nullopt); + return true; + } + + std::optional GetAdminSetting(StringAdminSetting setting) + { + // Check for a policy that overrides this setting. + auto policyState = GetPolicyStateForSetting(setting); + if (policyState) { - result.emplace_back(static_cast(i));; + return policyState.value(); } - return result; + AdminSettingsInternal adminSettingsInternal; + return adminSettingsInternal.GetAdminSettingValue(setting); + } + + std::vector GetAllBoolAdminSettings() + { + return GetAllSequentialEnumValues(BoolAdminSetting::Unknown); } + + std::vector GetAllStringAdminSettings() + { + return GetAllSequentialEnumValues(StringAdminSetting::Unknown); + } + } diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj index 298d81f5e2..f9dbdc9361 100644 --- a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj +++ b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj @@ -435,6 +435,7 @@ + @@ -481,6 +482,7 @@ + diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters index 85789ca484..ab890bd70f 100644 --- a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters +++ b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters @@ -189,6 +189,9 @@ Public\winget + + Public\winget + @@ -338,6 +341,9 @@ Authentication + + Source Files + diff --git a/src/AppInstallerCommonCore/Deployment.cpp b/src/AppInstallerCommonCore/Deployment.cpp index cdd87ea01e..08c5c84b26 100644 --- a/src/AppInstallerCommonCore/Deployment.cpp +++ b/src/AppInstallerCommonCore/Deployment.cpp @@ -114,6 +114,7 @@ namespace AppInstaller::Deployment PackageManager packageManager; // In the event of a failure we want to ensure that the package is not left on the system. + // No need for proxy as Deployment won't use it anyways. Msix::MsixInfo packageInfo{ uri }; std::wstring packageFullNameWide = packageInfo.GetPackageFullNameWide(); std::string packageFullName = Utility::ConvertToUTF8(packageFullNameWide); @@ -218,6 +219,7 @@ namespace AppInstaller::Deployment PackageManager packageManager; // In the event of a failure we want to ensure that the package is not left on the system. + // No need for proxy as Deployment won't use it anyways. Msix::MsixInfo packageInfo{ uri }; std::wstring packageFullNameWide = packageInfo.GetPackageFullNameWide(); std::string packageFullName = Utility::ConvertToUTF8(packageFullNameWide); diff --git a/src/AppInstallerCommonCore/Downloader.cpp b/src/AppInstallerCommonCore/Downloader.cpp index 748cce6de9..4f6098533f 100644 --- a/src/AppInstallerCommonCore/Downloader.cpp +++ b/src/AppInstallerCommonCore/Downloader.cpp @@ -9,6 +9,7 @@ #include "Public/AppInstallerLogging.h" #include "Public/AppInstallerTelemetry.h" #include "Public/winget/UserSettings.h" +#include "Public/winget/NetworkSettings.h" #include "Public/winget/Filesystem.h" #include "DODownloader.h" #include "HttpStream/HttpRandomAccessStream.h" @@ -103,12 +104,29 @@ namespace AppInstaller::Utility AICLI_LOG(Core, Info, << "WinINet downloading from url: " << url); auto agentWide = Utility::ConvertToUTF16(Runtime::GetDefaultUserAgent().get()); - wil::unique_hinternet session(InternetOpen( - agentWide.c_str(), - INTERNET_OPEN_TYPE_PRECONFIG, - NULL, - NULL, - 0)); + wil::unique_hinternet session; + + const auto& proxyUri = Network().GetProxyUri(); + if (proxyUri) + { + AICLI_LOG(Core, Info, << "Using proxy " << proxyUri.value()); + session.reset(InternetOpen( + agentWide.c_str(), + INTERNET_OPEN_TYPE_PROXY, + Utility::ConvertToUTF16(proxyUri.value()).c_str(), + NULL, + 0)); + } + else + { + session.reset(InternetOpen( + agentWide.c_str(), + INTERNET_OPEN_TYPE_PRECONFIG, + NULL, + NULL, + 0)); + } + THROW_LAST_ERROR_IF_NULL_MSG(session, "InternetOpen() failed."); auto urlWide = Utility::ConvertToUTF16(url); @@ -224,6 +242,7 @@ namespace AppInstaller::Utility std::map GetHeaders(std::string_view url) { + // TODO: Use proxy info. HttpClient does not support using a custom proxy, only using the system-wide one. AICLI_LOG(Core, Verbose, << "Retrieving headers from url: " << url); HttpBaseProtocolFilter filter; @@ -296,11 +315,7 @@ namespace AppInstaller::Utility // - WinGetUtil :: Intentionally not using DO at this time if (type == DownloadType::Installer) { - // Determine whether to try DO first or not, as this is the only choice currently supported. - InstallerDownloader setting = User().Get(); - - if (setting == InstallerDownloader::Default || - setting == InstallerDownloader::DeliveryOptimization) + if (Network().GetInstallerDownloader() == InstallerDownloader::DeliveryOptimization) { try { diff --git a/src/AppInstallerCommonCore/ExperimentalFeature.cpp b/src/AppInstallerCommonCore/ExperimentalFeature.cpp index 98dd70ce88..d531a36fe8 100644 --- a/src/AppInstallerCommonCore/ExperimentalFeature.cpp +++ b/src/AppInstallerCommonCore/ExperimentalFeature.cpp @@ -44,6 +44,8 @@ namespace AppInstaller::Settings return userSettings.Get(); case ExperimentalFeature::Feature::Configuration03: return userSettings.Get(); + case ExperimentalFeature::Feature::Proxy: + return userSettings.Get(); default: THROW_HR(E_UNEXPECTED); } @@ -77,6 +79,8 @@ namespace AppInstaller::Settings return ExperimentalFeature{ "Resume", "resume", "https://aka.ms/winget-settings", Feature::Resume }; case Feature::Configuration03: return ExperimentalFeature{ "Configuration Schema 0.3", "configuration03", "https://aka.ms/winget-settings", Feature::Configuration03 }; + case Feature::Proxy: + return ExperimentalFeature{ "Proxy", "proxy", "https://aka.ms/winget-settings", Feature::Proxy }; default: THROW_HR(E_UNEXPECTED); } diff --git a/src/AppInstallerCommonCore/HttpStream/HttpClientWrapper.cpp b/src/AppInstallerCommonCore/HttpStream/HttpClientWrapper.cpp index a9aedbb279..d5e1401965 100644 --- a/src/AppInstallerCommonCore/HttpStream/HttpClientWrapper.cpp +++ b/src/AppInstallerCommonCore/HttpStream/HttpClientWrapper.cpp @@ -22,6 +22,7 @@ namespace AppInstaller::Utility::HttpStream { std::future> HttpClientWrapper::CreateAsync(const Uri& uri) { + // TODO: Use proxy info. HttpClient does not support using a custom proxy, only using the system-wide one. std::shared_ptr instance = std::make_shared(); // Use an HTTP filter to disable the default caching behavior and use the Most Recent caching behavior instead diff --git a/src/AppInstallerCommonCore/HttpStream/HttpRandomAccessStream.h b/src/AppInstallerCommonCore/HttpStream/HttpRandomAccessStream.h index 6947be6578..0ed2d0c108 100644 --- a/src/AppInstallerCommonCore/HttpStream/HttpRandomAccessStream.h +++ b/src/AppInstallerCommonCore/HttpStream/HttpRandomAccessStream.h @@ -19,8 +19,7 @@ namespace AppInstaller::Utility::HttpStream winrt::Windows::Storage::Streams::IInputStream> { public: - winrt::Windows::Foundation::IAsyncOperation InitializeAsync( - const winrt::Windows::Foundation::Uri& uri); + winrt::Windows::Foundation::IAsyncOperation InitializeAsync(const winrt::Windows::Foundation::Uri& uri); uint64_t Size() const; void Size(uint64_t value); uint64_t Position() const; diff --git a/src/AppInstallerCommonCore/Manifest/MsixManifestValidation.cpp b/src/AppInstallerCommonCore/Manifest/MsixManifestValidation.cpp index c838d2e8d8..bd769a4d33 100644 --- a/src/AppInstallerCommonCore/Manifest/MsixManifestValidation.cpp +++ b/src/AppInstallerCommonCore/Manifest/MsixManifestValidation.cpp @@ -59,8 +59,8 @@ namespace AppInstaller::Manifest { AICLI_LOG(Core, Info, << "Start downloading installer"); auto tempFile = Runtime::GetNewTempFilePath(); - ProgressCallback callback; - Utility::Download(installerUrl, tempFile, Utility::DownloadType::Installer, callback); + ProgressCallback emptyCallback; + Utility::Download(installerUrl, tempFile, Utility::DownloadType::Installer, emptyCallback); m_downloadedInstallers.push_back(tempFile); return tempFile; } diff --git a/src/AppInstallerCommonCore/NetworkSettings.cpp b/src/AppInstallerCommonCore/NetworkSettings.cpp new file mode 100644 index 0000000000..34ef02d5bf --- /dev/null +++ b/src/AppInstallerCommonCore/NetworkSettings.cpp @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "winget/NetworkSettings.h" +#include "winget/AdminSettings.h" +#include "AppInstallerLogging.h" + +namespace AppInstaller::Settings +{ + void NetworkSettings::SetProxyUri(const std::optional& proxyUri) + { + AICLI_LOG(Core, Info, << "Setting proxy"); + + if (proxyUri) + { + m_proxyUri = proxyUri.value(); + AICLI_LOG(Core, Info, << "New value for proxy is " << m_proxyUri.value()); + } + else + { + m_proxyUri.reset(); + AICLI_LOG(Core, Info, << "Proxy will not be used"); + } + } + + InstallerDownloader NetworkSettings::GetInstallerDownloader() const + { + // The default is DeliveryOptimization. + // We only use WinINet if specified by settings, or if we want to use proxy (as DO does not support that) + InstallerDownloader setting = User().Get(); + + if (setting != InstallerDownloader::WinInet && m_proxyUri) + { + AICLI_LOG(Core, Info, << "Forcing use of wininet for download as DO does not support proxy"); + return InstallerDownloader::WinInet; + } + else // Default or DO + { + return InstallerDownloader::DeliveryOptimization; + } + } + + NetworkSettings::NetworkSettings() + { + // Get the default proxy + m_proxyUri = GetAdminSetting(StringAdminSetting::DefaultProxy); + AICLI_LOG(Core, Info, << "Default proxy is " << (m_proxyUri ? m_proxyUri.value() : "not set")); + } + + NetworkSettings& NetworkSettings::Instance() + { + static NetworkSettings networkSettings; + return networkSettings; + } + + NetworkSettings& Network() + { + return NetworkSettings::Instance(); + } +} \ No newline at end of file diff --git a/src/AppInstallerCommonCore/Public/AppInstallerDownloader.h b/src/AppInstallerCommonCore/Public/AppInstallerDownloader.h index c99e10767c..1850a44be6 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerDownloader.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerDownloader.h @@ -4,11 +4,6 @@ #include #include -#include - -#include -#include - #include #include #include @@ -56,27 +51,27 @@ namespace AppInstaller::Utility // url: The url to be downloaded from. http->https redirection is allowed. // dest: The stream to be downloaded to. // computeHash: Optional. Indicates if SHA256 hash should be calculated when downloading. - // downloadIdentifier: Optional. Currently only used by DO to identify the download. + // downloadInfo: Optional. Currently only used by DO to identify the download. std::optional> DownloadToStream( const std::string& url, std::ostream& dest, DownloadType type, IProgressCallback& progress, bool computeHash = false, - std::optional info = {}); + std::optional downloadInfo = {}); // Downloads a file from the given URL and places it in the given location. // url: The url to be downloaded from. http->https redirection is allowed. // dest: The path to local file to be downloaded to. // computeHash: Optional. Indicates if SHA256 hash should be calculated when downloading. - // downloadIdentifier: Optional. Currently only used by DO to identify the download. + // downloadInfo: Optional. Currently only used by DO to identify the download. std::optional> Download( const std::string& url, const std::filesystem::path& dest, DownloadType type, IProgressCallback& progress, bool computeHash = false, - std::optional info = {}); + std::optional downloadInfo = {}); // Gets the headers for the given URL. std::map GetHeaders(std::string_view url); @@ -100,7 +95,7 @@ namespace AppInstaller::Utility HRESULT ApplyMotwUsingIAttachmentExecuteIfApplicable(const std::filesystem::path& filePath, const std::string& source, URLZONE zoneIfScanFailure); // Function to read-only create a stream from a uri string (url address or file system path) - Microsoft::WRL::ComPtr GetReadOnlyStreamFromURI(std::string_view uriStr); + ::Microsoft::WRL::ComPtr GetReadOnlyStreamFromURI(std::string_view uriStr); // Gets the retry after value in terms of a delay in seconds. std::chrono::seconds GetRetryAfter(const std::wstring& retryAfter); diff --git a/src/AppInstallerCommonCore/Public/winget/AdminSettings.h b/src/AppInstallerCommonCore/Public/winget/AdminSettings.h index 4641d84225..09d77fff6f 100644 --- a/src/AppInstallerCommonCore/Public/winget/AdminSettings.h +++ b/src/AppInstallerCommonCore/Public/winget/AdminSettings.h @@ -4,28 +4,52 @@ #include +#ifndef AICLI_DISABLE_TEST_HOOKS +#include "winget/GroupPolicy.h" +#endif + namespace AppInstaller::Settings { // Enum of admin settings. - enum class AdminSetting + enum class BoolAdminSetting : size_t { Unknown = 0, LocalManifestFiles, BypassCertificatePinningForMicrosoftStore, InstallerHashOverride, LocalArchiveMalwareScanOverride, + ProxyCommandLineOptions, + Max, + }; + + enum class StringAdminSetting : size_t + { + Unknown = 0, + DefaultProxy, Max, }; - AdminSetting StringToAdminSetting(std::string_view in); + BoolAdminSetting StringToBoolAdminSetting(std::string_view in); + StringAdminSetting StringToStringAdminSetting(std::string_view in); - Utility::LocIndView AdminSettingToString(AdminSetting setting); + Utility::LocIndView AdminSettingToString(BoolAdminSetting setting); + Utility::LocIndView AdminSettingToString(StringAdminSetting setting); - bool EnableAdminSetting(AdminSetting setting); + // Returns true if the value is set. + // Group policy overriding the setting can prevent the value from being set + bool EnableAdminSetting(BoolAdminSetting setting); + bool DisableAdminSetting(BoolAdminSetting setting); + bool SetAdminSetting(StringAdminSetting setting, std::string_view value); + bool ResetAdminSetting(StringAdminSetting setting); - bool DisableAdminSetting(AdminSetting setting); + bool IsAdminSettingEnabled(BoolAdminSetting setting); + std::optional GetAdminSetting(StringAdminSetting setting); - bool IsAdminSettingEnabled(AdminSetting setting); + std::vector GetAllBoolAdminSettings(); + std::vector GetAllStringAdminSettings(); - std::vector GetAllAdminSettings(); +#ifndef AICLI_DISABLE_TEST_HOOKS + // Only exposed for tests to validate that all admin settings have a corresponding policy + TogglePolicy::Policy GetAdminSettingPolicy(BoolAdminSetting setting); +#endif } diff --git a/src/AppInstallerCommonCore/Public/winget/ExperimentalFeature.h b/src/AppInstallerCommonCore/Public/winget/ExperimentalFeature.h index 72cad2a480..e2847cd0a4 100644 --- a/src/AppInstallerCommonCore/Public/winget/ExperimentalFeature.h +++ b/src/AppInstallerCommonCore/Public/winget/ExperimentalFeature.h @@ -25,6 +25,7 @@ namespace AppInstaller::Settings DirectMSI = 0x1, Resume = 0x2, Configuration03 = 0x4, + Proxy = 0x8, Max, // This MUST always be after all experimental features // Features listed after Max will not be shown with the features command diff --git a/src/AppInstallerCommonCore/Public/winget/NetworkSettings.h b/src/AppInstallerCommonCore/Public/winget/NetworkSettings.h new file mode 100644 index 0000000000..856055fcc8 --- /dev/null +++ b/src/AppInstallerCommonCore/Public/winget/NetworkSettings.h @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once + +#include +#include +#include "winget/UserSettings.h" + +namespace AppInstaller::Settings +{ + // Network related settings. + // Merges information from user settings, admin settings, command line, and group policy. + // TODO: This is currently a process global. It should be converted to a thread local + // (like telemetry) once we expose configuring a proxy through the COM API + struct NetworkSettings + { + static NetworkSettings& Instance(); + + const std::optional GetProxyUri() const { return m_proxyUri; } + // Sets the proxy URI; may do nothing depending on admin settings and group policy + void SetProxyUri(const std::optional& proxyUri); + + InstallerDownloader GetInstallerDownloader() const; + + protected: + NetworkSettings(); + ~NetworkSettings() = default; + + std::optional m_proxyUri; + }; + + NetworkSettings& Network(); +} \ No newline at end of file diff --git a/src/AppInstallerCommonCore/Public/winget/UserSettings.h b/src/AppInstallerCommonCore/Public/winget/UserSettings.h index ad63b65c44..ba156f8cf8 100644 --- a/src/AppInstallerCommonCore/Public/winget/UserSettings.h +++ b/src/AppInstallerCommonCore/Public/winget/UserSettings.h @@ -72,6 +72,7 @@ namespace AppInstaller::Settings EFDirectMSI, EFResume, EFConfiguration03, + EFProxy, // Telemetry TelemetryDisable, // Install behavior @@ -151,6 +152,7 @@ namespace AppInstaller::Settings SETTINGMAPPING_SPECIALIZATION(Setting::EFDirectMSI, bool, bool, false, ".experimentalFeatures.directMSI"sv); SETTINGMAPPING_SPECIALIZATION(Setting::EFResume, bool, bool, false, ".experimentalFeatures.resume"sv); SETTINGMAPPING_SPECIALIZATION(Setting::EFConfiguration03, bool, bool, false, ".experimentalFeatures.configuration03"sv); + SETTINGMAPPING_SPECIALIZATION(Setting::EFProxy, bool, bool, false, ".experimentalFeatures.proxy"sv); // Telemetry SETTINGMAPPING_SPECIALIZATION(Setting::TelemetryDisable, bool, bool, false, ".telemetry.disable"sv); // Install behavior diff --git a/src/AppInstallerCommonCore/UserSettings.cpp b/src/AppInstallerCommonCore/UserSettings.cpp index bc02392383..12d4d378aa 100644 --- a/src/AppInstallerCommonCore/UserSettings.cpp +++ b/src/AppInstallerCommonCore/UserSettings.cpp @@ -261,6 +261,7 @@ namespace AppInstaller::Settings WINGET_VALIDATE_PASS_THROUGH(EFDirectMSI) WINGET_VALIDATE_PASS_THROUGH(EFResume) WINGET_VALIDATE_PASS_THROUGH(EFConfiguration03) + WINGET_VALIDATE_PASS_THROUGH(EFProxy) WINGET_VALIDATE_PASS_THROUGH(AnonymizePathForDisplay) WINGET_VALIDATE_PASS_THROUGH(TelemetryDisable) WINGET_VALIDATE_PASS_THROUGH(InteractivityDisable) diff --git a/src/AppInstallerRepositoryCore/Rest/RestClient.cpp b/src/AppInstallerRepositoryCore/Rest/RestClient.cpp index d085757c92..900a4a895e 100644 --- a/src/AppInstallerRepositoryCore/Rest/RestClient.cpp +++ b/src/AppInstallerRepositoryCore/Rest/RestClient.cpp @@ -148,37 +148,38 @@ namespace AppInstaller::Repository::Rest const HttpClientHelper::HttpRequestHeaders& additionalHeaders, const IRestClient::Information& information, const Authentication::AuthenticationArguments& authArgs, - const Version& version) + const Version& version, + const HttpClientHelper& helper) { if (version == Version_1_0_0) { - return std::make_unique(api); + return std::make_unique(api, helper); } else if (version == Version_1_1_0) { - return std::make_unique(api, information, additionalHeaders); + return std::make_unique(api, helper, information, additionalHeaders); } else if (version == Version_1_4_0) { - return std::make_unique(api, information, additionalHeaders); + return std::make_unique(api, helper, information, additionalHeaders); } else if (version == Version_1_5_0) { - return std::make_unique(api, information, additionalHeaders); + return std::make_unique(api, helper, information, additionalHeaders); } else if (version == Version_1_6_0) { - return std::make_unique(api, information, additionalHeaders); + return std::make_unique(api, helper, information, additionalHeaders); } else if (version == Version_1_7_0) { - return std::make_unique(api, information, additionalHeaders, authArgs); + return std::make_unique(api, helper, information, additionalHeaders, authArgs); } THROW_HR(APPINSTALLER_CLI_ERROR_RESTSOURCE_INVALID_VERSION); } - RestClient RestClient::Create(const std::string& restApi, std::optional customHeader, std::string_view caller, const Authentication::AuthenticationArguments& authArgs, const HttpClientHelper& helper) + RestClient RestClient::Create(const std::string& restApi, std::optional customHeader, std::string_view caller, const HttpClientHelper& helper, const Authentication::AuthenticationArguments& authArgs) { utility::string_t restEndpoint = RestHelper::GetRestAPIBaseUri(restApi); THROW_HR_IF(APPINSTALLER_CLI_ERROR_RESTSOURCE_INVALID_URL, !RestHelper::IsValidUri(restEndpoint)); @@ -189,7 +190,7 @@ namespace AppInstaller::Repository::Rest std::optional latestCommonVersion = GetLatestCommonVersion(information.ServerSupportedVersions, WingetSupportedContracts); THROW_HR_IF(APPINSTALLER_CLI_ERROR_UNSUPPORTED_RESTSOURCE, !latestCommonVersion); - std::unique_ptr supportedInterface = GetSupportedInterface(utility::conversions::to_utf8string(restEndpoint), headers, information, authArgs, latestCommonVersion.value()); + std::unique_ptr supportedInterface = GetSupportedInterface(utility::conversions::to_utf8string(restEndpoint), headers, information, authArgs, latestCommonVersion.value(), helper); return RestClient{ std::move(supportedInterface), information.SourceIdentifier }; } } diff --git a/src/AppInstallerRepositoryCore/Rest/RestClient.h b/src/AppInstallerRepositoryCore/Rest/RestClient.h index 64bb1f5989..e7ee2c7313 100644 --- a/src/AppInstallerRepositoryCore/Rest/RestClient.h +++ b/src/AppInstallerRepositoryCore/Rest/RestClient.h @@ -30,12 +30,18 @@ namespace AppInstaller::Repository::Rest static std::optional GetLatestCommonVersion(const std::vector& serverSupportedVersions, const std::set& wingetSupportedVersions); // Responsible for getting the source information contracts with minimal validation. Does not try to create a rest interface out of it. - static Schema::IRestClient::Information GetInformation(const std::string& restApi, std::optional customHeader, std::string_view caller, const Schema::HttpClientHelper& helper = {}); + static Schema::IRestClient::Information GetInformation(const std::string& restApi, std::optional customHeader, std::string_view caller, const Schema::HttpClientHelper& helper); - static std::unique_ptr GetSupportedInterface(const std::string& restApi, const Schema::HttpClientHelper::HttpRequestHeaders& additionalHeaders, const Schema::IRestClient::Information& information, const Authentication::AuthenticationArguments& authArgs, const AppInstaller::Utility::Version& version); + static std::unique_ptr GetSupportedInterface( + const std::string& restApi, + const Schema::HttpClientHelper::HttpRequestHeaders& additionalHeaders, + const Schema::IRestClient::Information& information, + const Authentication::AuthenticationArguments& authArgs, + const AppInstaller::Utility::Version& version, + const Schema::HttpClientHelper& helper); // Creates the rest client. Full validation performed (just as opening the source) - static RestClient Create(const std::string& restApi, std::optional customHeader, std::string_view caller, const Authentication::AuthenticationArguments& authArgs = {}, const Schema::HttpClientHelper& helper = {}); + static RestClient Create(const std::string& restApi, std::optional customHeader, std::string_view caller, const Schema::HttpClientHelper& helper, const Authentication::AuthenticationArguments& authArgs = {}); private: RestClient(std::unique_ptr supportedInterface, std::string sourceIdentifier); diff --git a/src/AppInstallerRepositoryCore/Rest/RestSourceFactory.cpp b/src/AppInstallerRepositoryCore/Rest/RestSourceFactory.cpp index 29367d9724..ff9be0ddbb 100644 --- a/src/AppInstallerRepositoryCore/Rest/RestSourceFactory.cpp +++ b/src/AppInstallerRepositoryCore/Rest/RestSourceFactory.cpp @@ -50,7 +50,7 @@ namespace AppInstaller::Repository::Rest std::shared_ptr Open(IProgressCallback&) override { Initialize(); - RestClient restClient = RestClient::Create(m_details.Arg, m_customHeader, m_caller, m_authArgs, m_httpClientHelper); + RestClient restClient = RestClient::Create(m_details.Arg, m_customHeader, m_caller, m_httpClientHelper, m_authArgs); return std::make_shared(m_details, m_information, std::move(restClient)); } diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_0/Interface.h b/src/AppInstallerRepositoryCore/Rest/Schema/1_0/Interface.h index 0ea59b2dfc..a304a9bae7 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_0/Interface.h +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_0/Interface.h @@ -10,7 +10,7 @@ namespace AppInstaller::Repository::Rest::Schema::V1_0 // Interface to this schema version exposed through IRestClient. struct Interface : public IRestClient { - Interface(const std::string& restApi, const HttpClientHelper& httpClientHelper = {}); + Interface(const std::string& restApi, const Schema::HttpClientHelper& helper); Interface(const Interface&) = delete; Interface& operator=(const Interface&) = delete; diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Interface.h b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Interface.h index 31575a7c51..8bf3629b69 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Interface.h +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Interface.h @@ -8,7 +8,7 @@ namespace AppInstaller::Repository::Rest::Schema::V1_1 // Interface to this schema version exposed through IRestClient. struct Interface : public V1_0::Interface { - Interface(const std::string& restApi, IRestClient::Information information, const HttpClientHelper::HttpRequestHeaders& additionalHeaders = {}, const HttpClientHelper& httpClientHelper = {}); + Interface(const std::string& restApi, const Schema::HttpClientHelper& helper, IRestClient::Information information, const HttpClientHelper::HttpRequestHeaders& additionalHeaders = {}); Interface(const Interface&) = delete; Interface& operator=(const Interface&) = delete; diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/RestInterface_1_1.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/RestInterface_1_1.cpp index 7fdaa5f2b1..23589e67a4 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/RestInterface_1_1.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/RestInterface_1_1.cpp @@ -26,9 +26,9 @@ namespace AppInstaller::Repository::Rest::Schema::V1_1 Interface::Interface( const std::string& restApi, + const HttpClientHelper& httpClientHelper, IRestClient::Information information, - const HttpClientHelper::HttpRequestHeaders& additionalHeaders, - const HttpClientHelper& httpClientHelper) : V1_0::Interface(restApi, httpClientHelper), m_information(std::move(information)) + const HttpClientHelper::HttpRequestHeaders& additionalHeaders) : V1_0::Interface(restApi, httpClientHelper), m_information(std::move(information)) { m_requiredRestApiHeaders[JSON::GetUtilityString(ContractVersion)] = JSON::GetUtilityString(Version_1_1_0.ToString()); diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_4/Interface.h b/src/AppInstallerRepositoryCore/Rest/Schema/1_4/Interface.h index cd8b2d63a7..c08ab1b875 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_4/Interface.h +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_4/Interface.h @@ -8,7 +8,7 @@ namespace AppInstaller::Repository::Rest::Schema::V1_4 // Interface to this schema version exposed through IRestClient. struct Interface : public V1_1::Interface { - Interface(const std::string& restApi, IRestClient::Information information, const HttpClientHelper::HttpRequestHeaders& additionalHeaders = {}, const HttpClientHelper& httpClientHelper = {}); + Interface(const std::string& restApi, const Schema::HttpClientHelper& helper, IRestClient::Information information, const HttpClientHelper::HttpRequestHeaders& additionalHeaders = {}); Interface(const Interface&) = delete; Interface& operator=(const Interface&) = delete; diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_4/RestInterface_1_4.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_4/RestInterface_1_4.cpp index 9ade746c48..fc7a0b8656 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_4/RestInterface_1_4.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_4/RestInterface_1_4.cpp @@ -11,9 +11,9 @@ namespace AppInstaller::Repository::Rest::Schema::V1_4 { Interface::Interface( const std::string& restApi, + const HttpClientHelper& httpClientHelper, IRestClient::Information information, - const HttpClientHelper::HttpRequestHeaders& additionalHeaders, - const HttpClientHelper& httpClientHelper) : V1_1::Interface(restApi, std::move(information), additionalHeaders, httpClientHelper) + const HttpClientHelper::HttpRequestHeaders& additionalHeaders) : V1_1::Interface(restApi, httpClientHelper, std::move(information), additionalHeaders) { m_requiredRestApiHeaders[JSON::GetUtilityString(ContractVersion)] = JSON::GetUtilityString(Version_1_4_0.ToString()); } diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_5/Interface.h b/src/AppInstallerRepositoryCore/Rest/Schema/1_5/Interface.h index aa47758c9c..51b8ddd4fb 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_5/Interface.h +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_5/Interface.h @@ -8,7 +8,7 @@ namespace AppInstaller::Repository::Rest::Schema::V1_5 // Interface to this schema version exposed through IRestClient. struct Interface : public V1_4::Interface { - Interface(const std::string& restApi, IRestClient::Information information, const HttpClientHelper::HttpRequestHeaders& additionalHeaders = {}, const HttpClientHelper& httpClientHelper = {}); + Interface(const std::string& restApi, const Schema::HttpClientHelper& helper, IRestClient::Information information, const HttpClientHelper::HttpRequestHeaders& additionalHeaders = {}); Interface(const Interface&) = delete; Interface& operator=(const Interface&) = delete; diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_5/RestInterface_1_5.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_5/RestInterface_1_5.cpp index 92da210126..82aa257bb5 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_5/RestInterface_1_5.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_5/RestInterface_1_5.cpp @@ -11,9 +11,9 @@ namespace AppInstaller::Repository::Rest::Schema::V1_5 { Interface::Interface( const std::string& restApi, + const HttpClientHelper& httpClientHelper, IRestClient::Information information, - const HttpClientHelper::HttpRequestHeaders& additionalHeaders, - const HttpClientHelper& httpClientHelper) : V1_4::Interface(restApi, std::move(information), additionalHeaders, httpClientHelper) + const HttpClientHelper::HttpRequestHeaders& additionalHeaders) : V1_4::Interface(restApi, httpClientHelper, std::move(information), additionalHeaders) { m_requiredRestApiHeaders[JSON::GetUtilityString(ContractVersion)] = JSON::GetUtilityString(Version_1_5_0.ToString()); } diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_6/Interface.h b/src/AppInstallerRepositoryCore/Rest/Schema/1_6/Interface.h index 49bc919d24..527017931e 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_6/Interface.h +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_6/Interface.h @@ -8,7 +8,7 @@ namespace AppInstaller::Repository::Rest::Schema::V1_6 // Interface to this schema version exposed through IRestClient. struct Interface : public V1_5::Interface { - Interface(const std::string& restApi, IRestClient::Information information, const HttpClientHelper::HttpRequestHeaders& additionalHeaders = {}, const HttpClientHelper& httpClientHelper = {}); + Interface(const std::string& restApi, const Schema::HttpClientHelper& helper, IRestClient::Information information, const HttpClientHelper::HttpRequestHeaders& additionalHeaders = {}); Interface(const Interface&) = delete; Interface& operator=(const Interface&) = delete; diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_6/RestInterface_1_6.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_6/RestInterface_1_6.cpp index 454476bce8..4277b683ac 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_6/RestInterface_1_6.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_6/RestInterface_1_6.cpp @@ -11,9 +11,9 @@ namespace AppInstaller::Repository::Rest::Schema::V1_6 { Interface::Interface( const std::string& restApi, + const HttpClientHelper& httpClientHelper, IRestClient::Information information, - const HttpClientHelper::HttpRequestHeaders& additionalHeaders, - const HttpClientHelper& httpClientHelper) : V1_5::Interface(restApi, std::move(information), additionalHeaders, httpClientHelper) + const HttpClientHelper::HttpRequestHeaders& additionalHeaders) : V1_5::Interface(restApi, httpClientHelper, std::move(information), additionalHeaders) { m_requiredRestApiHeaders[JSON::GetUtilityString(ContractVersion)] = JSON::GetUtilityString(Version_1_6_0.ToString()); } diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_7/Interface.h b/src/AppInstallerRepositoryCore/Rest/Schema/1_7/Interface.h index 5c51327998..911cc1a37d 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_7/Interface.h +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_7/Interface.h @@ -8,7 +8,7 @@ namespace AppInstaller::Repository::Rest::Schema::V1_7 // Interface to this schema version exposed through IRestClient. struct Interface : public V1_6::Interface { - Interface(const std::string& restApi, IRestClient::Information information, const HttpClientHelper::HttpRequestHeaders& additionalHeaders = {}, Authentication::AuthenticationArguments authArgs = {}, const HttpClientHelper& httpClientHelper = {}); + Interface(const std::string& restApi, const Schema::HttpClientHelper& helper, IRestClient::Information information, const HttpClientHelper::HttpRequestHeaders& additionalHeaders = {}, Authentication::AuthenticationArguments authArgs = {}); Interface(const Interface&) = delete; Interface& operator=(const Interface&) = delete; diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_7/RestInterface_1_7.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_7/RestInterface_1_7.cpp index 0ed0e370a9..96108aa0f6 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_7/RestInterface_1_7.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_7/RestInterface_1_7.cpp @@ -11,10 +11,10 @@ namespace AppInstaller::Repository::Rest::Schema::V1_7 { Interface::Interface( const std::string& restApi, + const HttpClientHelper& httpClientHelper, IRestClient::Information information, const HttpClientHelper::HttpRequestHeaders& additionalHeaders, - Authentication::AuthenticationArguments authArgs, - const HttpClientHelper& httpClientHelper) : V1_6::Interface(restApi, std::move(information), additionalHeaders, httpClientHelper), m_authArgs(std::move(authArgs)) + Authentication::AuthenticationArguments authArgs) : V1_6::Interface(restApi, httpClientHelper, std::move(information), additionalHeaders), m_authArgs(std::move(authArgs)) { m_requiredRestApiHeaders[JSON::GetUtilityString(ContractVersion)] = JSON::GetUtilityString(Version_1_7_0.ToString()); diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/HttpClientHelper.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/HttpClientHelper.cpp index 51276c1d7b..8d4c316171 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/HttpClientHelper.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/HttpClientHelper.cpp @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "pch.h" #include "HttpClientHelper.h" +#include namespace AppInstaller::Repository::Rest::Schema { @@ -42,7 +43,20 @@ namespace AppInstaller::Repository::Rest::Schema } } - HttpClientHelper::HttpClientHelper(std::shared_ptr stage) : m_defaultRequestHandlerStage(std::move(stage)) {} + HttpClientHelper::HttpClientHelper(std::shared_ptr stage) + : m_defaultRequestHandlerStage(std::move(stage)) + { + const auto& proxyUri = Settings::Network().GetProxyUri(); + if (proxyUri) + { + AICLI_LOG(Repo, Info, << "Setting proxy for REST HTTP Client helper to " << proxyUri.value()); + m_clientConfig.set_proxy(web::web_proxy{ Utility::ConvertToUTF16(proxyUri.value()) }); + } + else + { + AICLI_LOG(Repo, Info, << "REST HTTP Client helper does not use proxy"); + } + } pplx::task HttpClientHelper::Post( const utility::string_t& uri, diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/HttpClientHelper.h b/src/AppInstallerRepositoryCore/Rest/Schema/HttpClientHelper.h index c7938c3329..9164270713 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/HttpClientHelper.h +++ b/src/AppInstallerRepositoryCore/Rest/Schema/HttpClientHelper.h @@ -26,6 +26,7 @@ namespace AppInstaller::Repository::Rest::Schema std::optional HandleGet(const utility::string_t& uri, const HttpRequestHeaders& headers = {}, const HttpRequestHeaders& authHeaders = {}) const; void SetPinningConfiguration(const Certificates::PinningConfiguration& configuration); + protected: std::optional ValidateAndExtractResponse(const web::http::http_response& response) const; diff --git a/src/AppInstallerRepositoryCore/SourceList.cpp b/src/AppInstallerRepositoryCore/SourceList.cpp index c934e75847..197a19f4f1 100644 --- a/src/AppInstallerRepositoryCore/SourceList.cpp +++ b/src/AppInstallerRepositoryCore/SourceList.cpp @@ -316,7 +316,7 @@ namespace AppInstaller::Repository details.TrustLevel = SourceTrustLevel::Trusted; details.SupportInstalledSearchCorrelation = false; - if (!Settings::IsAdminSettingEnabled(Settings::AdminSetting::BypassCertificatePinningForMicrosoftStore)) + if (!Settings::IsAdminSettingEnabled(Settings::BoolAdminSetting::BypassCertificatePinningForMicrosoftStore)) { using namespace AppInstaller::Certificates; diff --git a/src/AppInstallerRepositoryCore/pch.h b/src/AppInstallerRepositoryCore/pch.h index 512990f9bd..fb24299526 100644 --- a/src/AppInstallerRepositoryCore/pch.h +++ b/src/AppInstallerRepositoryCore/pch.h @@ -20,23 +20,6 @@ #include #pragma warning( pop ) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include @@ -44,6 +27,7 @@ #include #include #include +#include #include #include @@ -77,3 +61,20 @@ #include #include #pragma warning( pop ) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/src/AppInstallerSharedLib/GroupPolicy.cpp b/src/AppInstallerSharedLib/GroupPolicy.cpp index 6777d000b0..7325203238 100644 --- a/src/AppInstallerSharedLib/GroupPolicy.cpp +++ b/src/AppInstallerSharedLib/GroupPolicy.cpp @@ -224,6 +224,13 @@ namespace AppInstaller::Settings namespace details { +#define POLICY_MAPPING_DEFAULT_READ(_policy_) \ + std::optional::value_t> ValuePolicyMapping<_policy_>::ReadAndValidate(const Registry::Key& policiesKey) \ + { \ + using Mapping = ValuePolicyMapping<_policy_>; \ + return GetRegistryValueData(policiesKey, Mapping::ValueName); \ + } + #define POLICY_MAPPING_DEFAULT_LIST_READ(_policy_) \ std::optional::value_t> ValuePolicyMapping<_policy_>::ReadAndValidate(const Registry::Key& policiesKey) \ { \ @@ -232,6 +239,7 @@ namespace AppInstaller::Settings POLICY_MAPPING_DEFAULT_LIST_READ(ValuePolicy::AdditionalSources); POLICY_MAPPING_DEFAULT_LIST_READ(ValuePolicy::AllowedSources); + POLICY_MAPPING_DEFAULT_READ(ValuePolicy::DefaultProxy); std::nullopt_t ValuePolicyMapping::ReadAndValidate(const Registry::Key&) { @@ -298,6 +306,8 @@ namespace AppInstaller::Settings return TogglePolicy(policy, "EnableWindowsPackageManagerCommandLineInterfaces"sv, String::PolicyEnableWindowsPackageManagerCommandLineInterfaces); case TogglePolicy::Policy::Configuration: return TogglePolicy(policy, "EnableWindowsPackageManagerConfiguration"sv, String::PolicyEnableWinGetConfiguration); + case TogglePolicy::Policy::ProxyCommandLineOptions: + return TogglePolicy(policy, "EnableWindowsPackageManagerProxyCommandLineOptions"sv, String::PolicyEnableProxyCommandLineOptions); default: THROW_HR(E_UNEXPECTED); } diff --git a/src/AppInstallerSharedLib/Public/AppInstallerLanguageUtilities.h b/src/AppInstallerSharedLib/Public/AppInstallerLanguageUtilities.h index 2a8f2c92fb..11cfefbab0 100644 --- a/src/AppInstallerSharedLib/Public/AppInstallerLanguageUtilities.h +++ b/src/AppInstallerSharedLib/Public/AppInstallerLanguageUtilities.h @@ -9,6 +9,7 @@ #include #include #include +#include namespace AppInstaller { @@ -144,6 +145,34 @@ namespace AppInstaller std::map m_data; }; + + template + std::vector GetAllSequentialEnumValues(E initialToSkip) + { + std::vector result; + using underlying_t = std::underlying_type_t; + + for (underlying_t i = 1 + static_cast(initialToSkip); i < static_cast(E::Max); ++i) + { + result.emplace_back(static_cast(i)); + } + + return result; + } + + template + std::vector GetAllExponentialEnumValues(E initialToSkip) + { + std::vector result; + using underlying_t = std::underlying_type_t; + + for (underlying_t i = 1 + static_cast(initialToSkip); i < static_cast(E::Max); i <<= 1) + { + result.emplace_back(static_cast(i)); + } + + return result; + } } // Enable enums to be output generically (as their integral value). diff --git a/src/AppInstallerSharedLib/Public/winget/GroupPolicy.h b/src/AppInstallerSharedLib/Public/winget/GroupPolicy.h index 96ca9396d4..114ef6703a 100644 --- a/src/AppInstallerSharedLib/Public/winget/GroupPolicy.h +++ b/src/AppInstallerSharedLib/Public/winget/GroupPolicy.h @@ -22,6 +22,7 @@ namespace AppInstaller::Settings SourceAutoUpdateIntervalInMinutes, AdditionalSources, AllowedSources, + DefaultProxy, Max, }; @@ -45,6 +46,7 @@ namespace AppInstaller::Settings BypassCertificatePinningForMicrosoftStore, WinGetCommandLineInterfaces, Configuration, + ProxyCommandLineOptions, Max, }; @@ -146,6 +148,7 @@ namespace AppInstaller::Settings ) POLICY_MAPPING_VALUE_SPECIALIZATION(ValuePolicy::SourceAutoUpdateIntervalInMinutes, uint32_t, "SourceAutoUpdateInterval"sv, Registry::Value::Type::DWord); + POLICY_MAPPING_VALUE_SPECIALIZATION(ValuePolicy::DefaultProxy, std::string, "DefaultProxy"sv, Registry::Value::Type::String); POLICY_MAPPING_LIST_SPECIALIZATION(ValuePolicy::AdditionalSources, SourceFromPolicy, "AdditionalSources"sv); POLICY_MAPPING_LIST_SPECIALIZATION(ValuePolicy::AllowedSources, SourceFromPolicy, "AllowedSources"sv); diff --git a/src/AppInstallerSharedLib/Public/winget/Resources.h b/src/AppInstallerSharedLib/Public/winget/Resources.h index ced47b8e5c..dc6591abd0 100644 --- a/src/AppInstallerSharedLib/Public/winget/Resources.h +++ b/src/AppInstallerSharedLib/Public/winget/Resources.h @@ -59,6 +59,7 @@ namespace AppInstaller WINGET_DEFINE_RESOURCE_STRINGID(PolicyEnableBypassCertificatePinningForMicrosoftStore); WINGET_DEFINE_RESOURCE_STRINGID(PolicyEnableWindowsPackageManagerCommandLineInterfaces); WINGET_DEFINE_RESOURCE_STRINGID(PolicyEnableWinGetConfiguration); + WINGET_DEFINE_RESOURCE_STRINGID(PolicyEnableProxyCommandLineOptions); WINGET_DEFINE_RESOURCE_STRINGID(SettingsWarningInvalidFieldFormat); WINGET_DEFINE_RESOURCE_STRINGID(SettingsWarningInvalidFieldValue); diff --git a/src/Microsoft.Management.Deployment/pch.h b/src/Microsoft.Management.Deployment/pch.h index b50e4d854b..47a1ae5ceb 100644 --- a/src/Microsoft.Management.Deployment/pch.h +++ b/src/Microsoft.Management.Deployment/pch.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include diff --git a/src/PowerShell/Microsoft.WinGet.SharedLib/Resources/GroupPolicyResource.Designer.cs b/src/PowerShell/Microsoft.WinGet.SharedLib/Resources/GroupPolicyResource.Designer.cs index c737994bc6..13d57659f4 100644 --- a/src/PowerShell/Microsoft.WinGet.SharedLib/Resources/GroupPolicyResource.Designer.cs +++ b/src/PowerShell/Microsoft.WinGet.SharedLib/Resources/GroupPolicyResource.Designer.cs @@ -150,6 +150,15 @@ internal static string PolicyEnableMSStoreSource { } } + /// + /// Looks up a localized string similar to Enable Windows Package Manager proxy command line options. + /// + internal static string PolicyEnableProxyCommandLineOptions { + get { + return ResourceManager.GetString("PolicyEnableProxyCommandLineOptions", resourceCulture); + } + } + /// /// Looks up a localized string similar to Enable Windows Package Manager command line interfaces. /// diff --git a/src/PowerShell/Microsoft.WinGet.SharedLib/Resources/GroupPolicyResource.resx b/src/PowerShell/Microsoft.WinGet.SharedLib/Resources/GroupPolicyResource.resx index f49d201ea4..60d79c6e0f 100644 --- a/src/PowerShell/Microsoft.WinGet.SharedLib/Resources/GroupPolicyResource.resx +++ b/src/PowerShell/Microsoft.WinGet.SharedLib/Resources/GroupPolicyResource.resx @@ -147,6 +147,9 @@ Enable Windows App Installer Microsoft Store Source + + Enable Windows Package Manager proxy command line options + Enable Windows Package Manager command line interfaces diff --git a/src/WinGetSchemas/WinGetSchemas.vcxitems b/src/WinGetSchemas/WinGetSchemas.vcxitems index c7e31821e5..36517bf71c 100644 --- a/src/WinGetSchemas/WinGetSchemas.vcxitems +++ b/src/WinGetSchemas/WinGetSchemas.vcxitems @@ -16,6 +16,7 @@ + diff --git a/src/WinGetSchemas/WinGetSchemas.vcxitems.filters b/src/WinGetSchemas/WinGetSchemas.vcxitems.filters index d81bd02d1e..de1a2218cc 100644 --- a/src/WinGetSchemas/WinGetSchemas.vcxitems.filters +++ b/src/WinGetSchemas/WinGetSchemas.vcxitems.filters @@ -18,6 +18,9 @@ packages + + settings + diff --git a/src/WinGetUtil/pch.h b/src/WinGetUtil/pch.h index 99d149eb3a..9136b0b146 100644 --- a/src/WinGetUtil/pch.h +++ b/src/WinGetUtil/pch.h @@ -19,3 +19,4 @@ #include #include +#include