using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
using Bit.Core.Exceptions;
using Bit.Core.Utilities;
namespace Bit.Core.AdminConsole.Utilities;
public static class PolicyDataValidator
{
///
/// Validates and serializes policy data based on the policy type.
///
/// The policy data to validate
/// The type of policy
/// Serialized JSON string if data is valid, null if data is null or empty
/// Thrown when data validation fails
public static string? ValidateAndSerialize(Dictionary? data, PolicyType policyType)
{
if (data == null || data.Count == 0)
{
return null;
}
try
{
var json = JsonSerializer.Serialize(data);
switch (policyType)
{
case PolicyType.MasterPassword:
var masterPasswordData = CoreHelpers.LoadClassFromJsonData(json);
ValidateModel(masterPasswordData, policyType);
break;
case PolicyType.SendOptions:
CoreHelpers.LoadClassFromJsonData(json);
break;
case PolicyType.ResetPassword:
CoreHelpers.LoadClassFromJsonData(json);
break;
}
return json;
}
catch (JsonException ex)
{
var fieldName = !string.IsNullOrEmpty(ex.Path) ? ex.Path.TrimStart('$', '.') : null;
var fieldInfo = !string.IsNullOrEmpty(fieldName) ? $": {fieldName} has an invalid value" : "";
throw new BadRequestException($"Invalid data for {policyType} policy{fieldInfo}.");
}
}
private static void ValidateModel(object model, PolicyType policyType)
{
var validationContext = new ValidationContext(model);
var validationResults = new List();
if (!Validator.TryValidateObject(model, validationContext, validationResults, true))
{
var errors = string.Join(", ", validationResults.Select(r => r.ErrorMessage));
throw new BadRequestException($"Invalid data for {policyType} policy: {errors}");
}
}
///
/// Validates and deserializes policy metadata based on the policy type.
///
/// The policy metadata to validate
/// The type of policy
/// Deserialized metadata model, or EmptyMetadataModel if metadata is null, empty, or validation fails
public static IPolicyMetadataModel ValidateAndDeserializeMetadata(Dictionary? metadata, PolicyType policyType)
{
if (metadata == null || metadata.Count == 0)
{
return new EmptyMetadataModel();
}
try
{
var json = JsonSerializer.Serialize(metadata);
return policyType switch
{
PolicyType.OrganizationDataOwnership =>
CoreHelpers.LoadClassFromJsonData(json),
_ => new EmptyMetadataModel()
};
}
catch (JsonException)
{
return new EmptyMetadataModel();
}
}
}