winget-cli

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

ConfigurationSetParser_0_3.cpp (15267B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "ConfigurationSetParser_0_3.h"
      5 #include "ParsingMacros.h"
      6 #include "ArgumentValidation.h"
      7 
      8 #include <AppInstallerErrors.h>
      9 #include <AppInstallerStrings.h>
     10 
     11 #include <sstream>
     12 
     13 using namespace AppInstaller::YAML;
     14 using namespace winrt::Windows::Foundation;
     15 
     16 namespace winrt::Microsoft::Management::Configuration::implementation
     17 {
     18     using IInspectable = winrt::Windows::Foundation::IInspectable;
     19 
     20     void ConfigurationSetParser_0_3::Parse()
     21     {
     22         auto result = make_self<implementation::ConfigurationSet>();
     23 
     24         CHECK_ERROR(ParseValueSet(m_document, ConfigurationField::Metadata, false, result->Metadata()));
     25 
     26         CHECK_ERROR(ExtractEnvironmentFromMetadata(result->Metadata(), result->EnvironmentInternal()));
     27 
     28         CHECK_ERROR(ParseParameters(result));
     29         CHECK_ERROR(ParseValueSet(m_document, ConfigurationField::Variables, false, result->Variables()));
     30 
     31         std::vector<Configuration::ConfigurationUnit> units;
     32         CHECK_ERROR(ParseConfigurationUnitsFromField(m_document, ConfigurationField::Resources, units));
     33         result->Units(std::move(units));
     34 
     35         result->SchemaVersion(GetSchemaVersion());
     36         m_configurationSet = std::move(result);
     37     }
     38 
     39     hstring ConfigurationSetParser_0_3::GetSchemaVersion()
     40     {
     41         static hstring s_schemaVersion{ L"0.3" };
     42         return s_schemaVersion;
     43     }
     44 
     45     void ConfigurationSetParser_0_3::SetDocument(AppInstaller::YAML::Node&& document)
     46     {
     47         m_document = std::move(document);
     48     }
     49 
     50     void ConfigurationSetParser_0_3::ParseParameters(ConfigurationSetParser::ConfigurationSetPtr& set)
     51     {
     52         std::vector<Configuration::ConfigurationParameter> parameters;
     53 
     54         ParseMapping(m_document, ConfigurationField::Parameters, false, Node::Type::Mapping, [&](std::string name, const Node& item)
     55             {
     56                 auto parameter = make_self<wil::details::module_count_wrapper<ConfigurationParameter>>();
     57                 CHECK_ERROR(ParseParameter(parameter.get(), item));
     58                 parameter->Name(hstring{ AppInstaller::Utility::ConvertToUTF16(name) });
     59                 parameters.emplace_back(*parameter);
     60             });
     61 
     62         set->Parameters(std::move(parameters));
     63     }
     64 
     65     void ConfigurationSetParser_0_3::ParseParameter(ConfigurationParameter* parameter, const AppInstaller::YAML::Node& node)
     66     {
     67         CHECK_ERROR(ParseParameterType(parameter, node));
     68         CHECK_ERROR(ParseValueSet(node, ConfigurationField::Metadata, false, parameter->Metadata()));
     69         CHECK_ERROR(GetStringValueForParameter(node, ConfigurationField::Description, parameter, &ConfigurationParameter::Description));
     70 
     71         PropertyType parameterType = parameter->Type();
     72         CHECK_ERROR(ParseObjectValueForParameter(node, ConfigurationField::DefaultValue, parameterType, parameter, &ConfigurationParameter::DefaultValue));
     73 
     74         std::vector<IInspectable> allowedValues;
     75 
     76         CHECK_ERROR(ParseSequence(node, ConfigurationField::AllowedValues, false, std::nullopt, [&](const Node& item)
     77             {
     78                 IInspectable object;
     79                 CHECK_ERROR(ParseObject(item, ConfigurationField::AllowedValues, parameterType, object));
     80                 allowedValues.emplace_back(std::move(object));
     81             }));
     82 
     83         if (!allowedValues.empty())
     84         {
     85             parameter->AllowedValues(std::move(allowedValues));
     86         }
     87 
     88         if (IsLengthType(parameterType))
     89         {
     90             CHECK_ERROR(GetUInt32ValueForParameter(node, ConfigurationField::MinimumLength, parameter, &ConfigurationParameter::MinimumLength));
     91             CHECK_ERROR(GetUInt32ValueForParameter(node, ConfigurationField::MaximumLength, parameter, &ConfigurationParameter::MaximumLength));
     92         }
     93         else
     94         {
     95             CHECK_ERROR(EnsureFieldAbsent(node, ConfigurationField::MinimumLength));
     96             CHECK_ERROR(EnsureFieldAbsent(node, ConfigurationField::MaximumLength));
     97         }
     98 
     99         if (IsComparableType(parameterType))
    100         {
    101             CHECK_ERROR(ParseObjectValueForParameter(node, ConfigurationField::MinimumValue, parameterType, parameter, &ConfigurationParameter::MinimumValue));
    102             CHECK_ERROR(ParseObjectValueForParameter(node, ConfigurationField::MaximumValue, parameterType, parameter, &ConfigurationParameter::MaximumValue));
    103         }
    104         else
    105         {
    106             CHECK_ERROR(EnsureFieldAbsent(node, ConfigurationField::MinimumValue));
    107             CHECK_ERROR(EnsureFieldAbsent(node, ConfigurationField::MaximumValue));
    108         }
    109     }
    110 
    111     void ConfigurationSetParser_0_3::ParseParameterType(ConfigurationParameter* parameter, const AppInstaller::YAML::Node& node)
    112     {
    113         const Node& typeNode = CHECK_ERROR(GetAndEnsureField(node, ConfigurationField::Type, true, Node::Type::Scalar));
    114         std::string typeValue = typeNode.as<std::string>();
    115         auto parsedType = ParseWindowsFoundationPropertyType(typeValue);
    116 
    117         if (parsedType)
    118         {
    119             parameter->Type(parsedType->first);
    120             parameter->IsSecure(parsedType->second);
    121         }
    122         else
    123         {
    124             FIELD_VALUE_ERROR(GetConfigurationFieldName(ConfigurationField::Type), typeValue, typeNode.Mark());
    125         }
    126     }
    127 
    128     void ConfigurationSetParser_0_3::GetStringValueForParameter(
    129         const Node& node,
    130         ConfigurationField field,
    131         ConfigurationParameter* parameter,
    132         void(ConfigurationParameter::* propertyFunction)(const hstring& value))
    133     {
    134         const Node& valueNode = CHECK_ERROR(GetAndEnsureField(node, field, false, Node::Type::Scalar));
    135 
    136         if (valueNode)
    137         {
    138             (parameter->*propertyFunction)(hstring{ valueNode.as<std::wstring>() });
    139         }
    140     }
    141 
    142     void ConfigurationSetParser_0_3::GetUInt32ValueForParameter(
    143         const AppInstaller::YAML::Node& node,
    144         ConfigurationField field,
    145         ConfigurationParameter* parameter,
    146         void(ConfigurationParameter::* propertyFunction)(uint32_t value))
    147     {
    148         const Node& valueNode = CHECK_ERROR(GetAndEnsureField(node, field, false, Node::Type::Scalar));
    149 
    150         if (valueNode)
    151         {
    152             int64_t value = valueNode.as<int64_t>();
    153             if (value < 0 || value > static_cast<int64_t>(std::numeric_limits<uint32_t>::max()))
    154             {
    155                 FIELD_VALUE_ERROR(GetConfigurationFieldName(field), valueNode.as<std::string>(), valueNode.Mark());
    156             }
    157             (parameter->*propertyFunction)(static_cast<uint32_t>(value));
    158         }
    159     }
    160 
    161     void ConfigurationSetParser_0_3::ParseObjectValueForParameter(
    162         const AppInstaller::YAML::Node& node,
    163         ConfigurationField field,
    164         PropertyType type,
    165         ConfigurationParameter* parameter,
    166         void(ConfigurationParameter::* propertyFunction)(const IInspectable& value))
    167     {
    168         const Node& valueNode = CHECK_ERROR(GetAndEnsureField(node, field, false, std::nullopt));
    169 
    170         if (valueNode)
    171         {
    172             IInspectable valueObject;
    173             CHECK_ERROR(ParseObject(valueNode, field, type, valueObject));
    174 
    175             (parameter->*propertyFunction)(valueObject);
    176         }
    177     }
    178 
    179     void ConfigurationSetParser_0_3::ParseConfigurationUnitsFromField(const Node& document, ConfigurationField field, std::vector<Configuration::ConfigurationUnit>& result)
    180     {
    181         ParseSequence(document, field, false, Node::Type::Mapping, [&](const Node& item)
    182             {
    183                 auto configurationUnit = make_self<ConfigurationUnit>();
    184                 ParseConfigurationUnit(configurationUnit.get(), item);
    185                 result.emplace_back(*configurationUnit);
    186             });
    187     }
    188 
    189     void ConfigurationSetParser_0_3::ParseConfigurationUnit(ConfigurationUnit* unit, const Node& unitNode)
    190     {
    191         // Set unknown intent as the new schema doesn't express it directly
    192         unit->Intent(ConfigurationUnitIntent::Unknown);
    193 
    194         CHECK_ERROR(GetStringValueForUnit(unitNode, ConfigurationField::Name, true, unit, &ConfigurationUnit::Identifier));
    195         CHECK_ERROR(GetStringValueForUnit(unitNode, ConfigurationField::Type, true, unit, &ConfigurationUnit::Type));
    196         CHECK_ERROR(ParseValueSet(unitNode, ConfigurationField::Metadata, false, unit->Metadata()));
    197         CHECK_ERROR(ExtractEnvironmentForUnit(unit));
    198         CHECK_ERROR(ValidateType(unit, unitNode, ConfigurationField::Type, false, true));
    199         CHECK_ERROR(GetStringArrayForUnit(unitNode, ConfigurationField::DependsOn, false, unit, &ConfigurationUnit::Dependencies));
    200 
    201         // Regardless of being a group or not, parse the settings.
    202         CHECK_ERROR(ParseValueSet(unitNode, ConfigurationField::Properties, false, unit->Settings()));
    203 
    204         if (ShouldConvertToGroup(unit))
    205         {
    206             unit->IsGroup(true);
    207 
    208             // TODO: The PS DSC v3 POR looks like it supports each group defining a new schema to be used for its group items.
    209             //       Consider supporting that in the future; but for now just use the same schema for everything.
    210             const Node& propertiesNode = GetAndEnsureField(unitNode, ConfigurationField::Properties, false, Node::Type::Mapping);
    211             if (propertiesNode)
    212             {
    213                 std::vector<Configuration::ConfigurationUnit> units;
    214                 CHECK_ERROR(ParseConfigurationUnitsFromField(propertiesNode, ConfigurationField::Resources, units));
    215                 unit->Units(std::move(units));
    216             }
    217         }
    218     }
    219 
    220     bool ConfigurationSetParser_0_3::ShouldConvertToGroup(ConfigurationUnit* unit)
    221     {
    222         // Allow the metadata to inform us that we should treat it as a group, including preventing a known type from being treated as one.
    223         auto isGroupObject = unit->Metadata().TryLookup(GetConfigurationFieldNameHString(ConfigurationField::IsGroupMetadata));
    224         if (isGroupObject)
    225         {
    226             auto isGroupProperty = isGroupObject.try_as<IPropertyValue>();
    227             if (isGroupProperty && isGroupProperty.Type() == PropertyType::Boolean)
    228             {
    229                 return isGroupProperty.GetBoolean();
    230             }
    231         }
    232 
    233         // TODO: Check for known types
    234 
    235         return false;
    236     }
    237 
    238     void ConfigurationSetParser_0_3::ExtractEnvironmentFromMetadata(Collections::ValueSet metadata, ConfigurationEnvironment& targetEnvironment)
    239     {
    240         auto root = TryLookupValueSet(metadata, ConfigurationField::WingetMetadataRoot);
    241         if (root)
    242         {
    243             // Get security context
    244             auto securityContext = TryLookupProperty(root, ConfigurationField::SecurityContextMetadata, PropertyType::String);
    245             if (securityContext)
    246             {
    247                 SecurityContext computedContext = SecurityContext::Current;
    248                 if (TryParseSecurityContext(securityContext.GetString(), computedContext))
    249                 {
    250                     targetEnvironment.Context(computedContext);
    251                 }
    252                 root.Remove(GetConfigurationFieldNameHString(ConfigurationField::SecurityContextMetadata));
    253             }
    254 
    255             // Get processor
    256             hstring processorFieldName = GetConfigurationFieldNameHString(ConfigurationField::ProcessorMetadata);
    257             IInspectable processor = root.TryLookup(processorFieldName);
    258             Collections::ValueSet processorValueSet = processor.try_as<Collections::ValueSet>();
    259             if (processorValueSet)
    260             {
    261                 targetEnvironment.ProcessorIdentifier({});
    262                 targetEnvironment.ProcessorProperties().Clear();
    263 
    264                 IPropertyValue identifier = TryLookupProperty(processorValueSet, ConfigurationField::ProcessorIdentifierMetadata, PropertyType::String);
    265                 if (identifier)
    266                 {
    267                     targetEnvironment.ProcessorIdentifier(identifier.GetString());
    268 
    269                     Collections::ValueSet processorSettings = TryLookupValueSet(processorValueSet, ConfigurationField::ProcessorPropertiesMetadata);
    270                     if (processorSettings)
    271                     {
    272                         targetEnvironment.ProcessorProperties(processorSettings);
    273                     }
    274                 }
    275 
    276                 root.Remove(processorFieldName);
    277             }
    278             else
    279             {
    280                 IPropertyValue processorProperty = processor.try_as<IPropertyValue>();
    281                 if (processorProperty)
    282                 {
    283                     targetEnvironment.ProcessorIdentifier(processorProperty.GetString());
    284                     targetEnvironment.ProcessorProperties().Clear();
    285                     root.Remove(processorFieldName);
    286                 }
    287             }
    288 
    289             if (root.Size() == 0)
    290             {
    291                 metadata.Remove(GetConfigurationFieldNameHString(ConfigurationField::WingetMetadataRoot));
    292             }
    293         }
    294     }
    295 
    296     void ConfigurationSetParser_0_3::ExtractEnvironmentForUnit(ConfigurationUnit* unit)
    297     {
    298         // Get unnested security context
    299         ExtractSecurityContext(unit);
    300 
    301         // Get nested environment
    302         ExtractEnvironmentFromMetadata(unit->Metadata(), unit->EnvironmentInternal());
    303     }
    304 
    305     std::optional<std::pair<PropertyType, bool>> ParseWindowsFoundationPropertyType(std::string_view value)
    306     {
    307         if (value == "string")
    308         {
    309             return std::make_pair(PropertyType::String, false);
    310         }
    311         else if (value == "securestring")
    312         {
    313             return std::make_pair(PropertyType::String, true);
    314         }
    315         else if (value == "int")
    316         {
    317             return std::make_pair(PropertyType::Int64, false);
    318         }
    319         else if (value == "bool")
    320         {
    321             return std::make_pair(PropertyType::Boolean, false);
    322         }
    323         else if (value == "object")
    324         {
    325             return std::make_pair(PropertyType::Inspectable, false);
    326         }
    327         else if (value == "secureobject")
    328         {
    329             return std::make_pair(PropertyType::Inspectable, true);
    330         }
    331         else if (value == "array")
    332         {
    333             return std::make_pair(PropertyType::InspectableArray, false);
    334         }
    335 
    336         // TODO: Consider supporting an expanded set of type strings
    337         return std::nullopt;
    338     }
    339 
    340     std::string_view ToString(PropertyType value, bool isSecure)
    341     {
    342         switch (value)
    343         {
    344         case PropertyType::Int16:
    345         case PropertyType::Int32:
    346         case PropertyType::Int64:
    347             return "int"sv;
    348         case PropertyType::Boolean:
    349             return "bool"sv;
    350         case PropertyType::String:
    351             return isSecure ? "securestring"sv : "string"sv;
    352         case PropertyType::Inspectable:
    353             return isSecure ? "secureobject"sv : "object"sv;
    354         case PropertyType::InspectableArray:
    355             return "array"sv;
    356         default:
    357             return {};
    358         }
    359     }
    360 }