winget-cli

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

DscAdminSettingsResource.cpp (10743B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "DscAdminSettingsResource.h"
      5 #include "DscComposableObject.h"
      6 #include "Resources.h"
      7 #include <winget/AdminSettings.h>
      8 
      9 using namespace AppInstaller::Utility::literals;
     10 using namespace AppInstaller::Repository;
     11 
     12 namespace AppInstaller::CLI
     13 {
     14     namespace AdminSettingsDetails
     15     {
     16         // The base for admin settings.
     17         struct IAdminSetting
     18         {
     19             virtual ~IAdminSetting() = default;
     20 
     21             // Gets the name of the setting.
     22             virtual Utility::LocIndView SettingName() const = 0;
     23 
     24             // Tests the value.
     25             // Returns true if in the desired state; false if not.
     26             virtual bool Test() const = 0;
     27 
     28             // Sets the value.
     29             // Returns true if the value could be set; false if not.
     30             virtual bool Set() const = 0;
     31         };
     32 
     33         // A boolean based admin setting
     34         struct AdminSetting_Bool : public IAdminSetting
     35         {
     36             AdminSetting_Bool(Settings::BoolAdminSetting setting, bool value) : m_setting(setting), m_value(value) {}
     37 
     38             Utility::LocIndView SettingName() const override
     39             {
     40                 return Settings::AdminSettingToString(m_setting);
     41             }
     42 
     43             bool Test() const override
     44             {
     45                 return Settings::IsAdminSettingEnabled(m_setting) == m_value;
     46             }
     47 
     48             bool Set() const override
     49             {
     50                 return m_value ? Settings::EnableAdminSetting(m_setting) : Settings::DisableAdminSetting(m_setting);
     51             }
     52 
     53         private:
     54             Settings::BoolAdminSetting m_setting;
     55             bool m_value;
     56         };
     57 
     58         // A string based admin setting
     59         struct AdminSetting_String : public IAdminSetting
     60         {
     61             AdminSetting_String(Settings::StringAdminSetting setting, std::optional<std::string> value) : m_setting(setting), m_value(std::move(value)) {}
     62 
     63             Utility::LocIndView SettingName() const override
     64             {
     65                 return Settings::AdminSettingToString(m_setting);
     66             }
     67 
     68             bool Test() const override
     69             {
     70                 return Settings::GetAdminSetting(m_setting) == m_value;
     71             }
     72 
     73             bool Set() const override
     74             {
     75                 return m_value ? Settings::SetAdminSetting(m_setting, m_value.value()) : Settings::ResetAdminSetting(m_setting);
     76             }
     77 
     78         private:
     79             Settings::StringAdminSetting m_setting;
     80             std::optional<std::string> m_value;
     81         };
     82     }
     83 
     84     namespace
     85     {
     86         WINGET_DSC_DEFINE_COMPOSABLE_PROPERTY(SettingsProperty, Json::Value, Settings, "settings", Resource::String::DscResourcePropertyDescriptionAdminSettingsSettings);
     87 
     88         using AdminSettingsResourceObject = DscComposableObject<StandardInDesiredStateProperty, SettingsProperty>;
     89 
     90         struct AdminSettingsFunctionData
     91         {
     92             AdminSettingsFunctionData() = default;
     93 
     94             AdminSettingsFunctionData(const std::optional<Json::Value>& json) :
     95                 Input(json)
     96             {
     97             }
     98 
     99             const AdminSettingsResourceObject Input;
    100             AdminSettingsResourceObject Output;
    101             std::vector<std::unique_ptr<AdminSettingsDetails::IAdminSetting>> InputSettings;
    102 
    103             // Converts the input settings into the appropriate settings object.
    104             void ParseSettings()
    105             {
    106                 if (Input.Settings())
    107                 {
    108                     const Json::Value& inputSettings = Input.Settings().value();
    109                     for (const auto& property : inputSettings.getMemberNames())
    110                     {
    111                         auto boolSetting = Settings::StringToBoolAdminSetting(property);
    112                         if (boolSetting != Settings::BoolAdminSetting::Unknown)
    113                         {
    114                             bool value = inputSettings[property].asBool();
    115                             AICLI_LOG(Config, Info, << "Bool admin setting: " << property << " => " << (value ? "true" : "false"));
    116                             InputSettings.emplace_back(std::make_unique<AdminSettingsDetails::AdminSetting_Bool>(boolSetting, value));
    117                             continue;
    118                         }
    119 
    120                         auto stringSetting = Settings::StringToStringAdminSetting(property);
    121                         if (stringSetting != Settings::StringAdminSetting::Unknown)
    122                         {
    123                             const auto& propertyNode = inputSettings[property];
    124                             std::optional<std::string> value;
    125 
    126                             if (propertyNode.isNull())
    127                             {
    128                                 AICLI_LOG(Config, Info, << "String admin setting: " << property << " => null");
    129                             }
    130                             else
    131                             {
    132                                 value = propertyNode.asString();
    133                                 AICLI_LOG(Config, Info, << "String admin setting: " << property << " => `" << value.value() << "`");
    134                             }
    135 
    136                             InputSettings.emplace_back(std::make_unique<AdminSettingsDetails::AdminSetting_String>(stringSetting, std::move(value)));
    137                             continue;
    138                         }
    139 
    140                         AICLI_LOG(Config, Warning, << "Unknown admin setting: " << property);
    141                     }
    142                 }
    143             }
    144 
    145             // Fills the Output object with the current state
    146             void Get()
    147             {
    148                 Json::Value adminSettings{ Json::objectValue };
    149 
    150                 for (const auto& setting : Settings::GetAllBoolAdminSettings())
    151                 {
    152                     auto str = std::string{ Settings::AdminSettingToString(setting) };
    153                     adminSettings[str] = Settings::IsAdminSettingEnabled(setting);
    154                 }
    155 
    156                 for (const auto& setting : Settings::GetAllStringAdminSettings())
    157                 {
    158                     auto name = std::string{ Settings::AdminSettingToString(setting) };
    159                     auto value = Settings::GetAdminSetting(setting);
    160                     if (value)
    161                     {
    162                         adminSettings[name] = value.value();
    163                     }
    164                 }
    165 
    166                 Output.Settings(std::move(adminSettings));
    167             }
    168 
    169             // Determines if the current Output values match the Input values state.
    170             bool Test()
    171             {
    172                 for (const auto& setting : InputSettings)
    173                 {
    174                     if (!setting->Test())
    175                     {
    176                         return false;
    177                     }
    178                 }
    179 
    180                 return true;
    181             }
    182 
    183             // Sets all of the input settings.
    184             void Set()
    185             {
    186                 for (const auto& setting : InputSettings)
    187                 {
    188                     if (!setting->Test())
    189                     {
    190                         if (!setting->Set())
    191                         {
    192                             auto message = Resource::String::DisabledByGroupPolicy(setting->SettingName());
    193                             THROW_HR_MSG(APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY, "%hs", message.get().c_str());
    194                         }
    195                     }
    196                 }
    197             }
    198 
    199             Json::Value DiffJson(bool inDesiredState)
    200             {
    201                 Json::Value result{ Json::ValueType::arrayValue };
    202 
    203                 if (!inDesiredState)
    204                 {
    205                     result.append(std::string{ SettingsProperty::Name() });
    206                 }
    207 
    208                 return result;
    209             }
    210         };
    211     }
    212 
    213     DscAdminSettingsResource::DscAdminSettingsResource(std::string_view parent) :
    214         DscCommandBase(parent, "admin-settings", DscResourceKind::Resource,
    215             DscFunctions::Get | DscFunctions::Set | DscFunctions::Test | DscFunctions::Export | DscFunctions::Schema,
    216             DscFunctionModifiers::ImplementsPretest | DscFunctionModifiers::ReturnsStateAndDiff)
    217     {
    218     }
    219 
    220     Resource::LocString DscAdminSettingsResource::ShortDescription() const
    221     {
    222         return Resource::String::DscAdminSettingsResourceShortDescription;
    223     }
    224 
    225     Resource::LocString DscAdminSettingsResource::LongDescription() const
    226     {
    227         return Resource::String::DscAdminSettingsResourceLongDescription;
    228     }
    229 
    230     std::string DscAdminSettingsResource::ResourceType() const
    231     {
    232         return "AdminSettings";
    233     }
    234 
    235     void DscAdminSettingsResource::ResourceFunctionGet(Execution::Context& context) const
    236     {
    237         AdminSettingsFunctionData data;
    238         data.Get();
    239         WriteJsonOutputLine(context, data.Output.ToJson());
    240     }
    241 
    242     void DscAdminSettingsResource::ResourceFunctionSet(Execution::Context& context) const
    243     {
    244         if (auto json = GetJsonFromInput(context))
    245         {
    246             AdminSettingsFunctionData data{ json };
    247 
    248             data.ParseSettings();
    249 
    250             bool inDesiredState = data.Test();
    251             if (!inDesiredState)
    252             {
    253                 Workflow::EnsureRunningAsAdmin(context);
    254 
    255                 if (context.IsTerminated())
    256                 {
    257                     return;
    258                 }
    259 
    260                 data.Set();
    261             }
    262 
    263             data.Get();
    264             WriteJsonOutputLine(context, data.Output.ToJson());
    265             WriteJsonOutputLine(context, data.DiffJson(inDesiredState));
    266         }
    267     }
    268 
    269     void DscAdminSettingsResource::ResourceFunctionTest(Execution::Context& context) const
    270     {
    271         if (auto json = GetJsonFromInput(context))
    272         {
    273             AdminSettingsFunctionData data{ json };
    274 
    275             data.ParseSettings();
    276 
    277             data.Get();
    278             data.Output.InDesiredState(data.Test());
    279 
    280             WriteJsonOutputLine(context, data.Output.ToJson());
    281             WriteJsonOutputLine(context, data.DiffJson(data.Output.InDesiredState().value()));
    282         }
    283     }
    284 
    285     void DscAdminSettingsResource::ResourceFunctionExport(Execution::Context& context) const
    286     {
    287         ResourceFunctionGet(context);
    288     }
    289 
    290     void DscAdminSettingsResource::ResourceFunctionSchema(Execution::Context& context) const
    291     {
    292         WriteJsonOutputLine(context, AdminSettingsResourceObject::Schema(ResourceType()));
    293     }
    294 }