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 }