Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #32

Merged
merged 2 commits into from
Feb 24, 2025
Merged

Dev #32

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<PackageReference Include="Ensure.That" Version="10.1.0" />
<PackageReference Include="FluentResults" Version="3.16.0" />
<PackageReference Include="Google.Protobuf" Version="3.29.3" />
<PackageReference Include="Jint" Version="4.2.0" />
<PackageReference Include="MediatR" Version="12.4.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.Analyzers" Version="9.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="9.0.1" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Text.Json;
using FluentResults;
using Jint;
using MediatR;

namespace Blocktrust.CredentialWorkflow.Core.Commands.ValidateCredentials.CustomValidation;

public class CustomValidationHandler : IRequestHandler<CustomValidationRequest, Result<CustomValidationResult>>
{
public async Task<Result<CustomValidationResult>> Handle(CustomValidationRequest request, CancellationToken cancellationToken)
{
var result = new CustomValidationResult();
var engine = new Engine();

try
{
// Convert data to JSON string for JavaScript engine
var dataJson = JsonSerializer.Serialize(request.Data);

// Set up the JavaScript environment
engine.SetValue("data", JsonSerializer.Deserialize<JsonElement>(dataJson));

foreach (var rule in request.Rules)
{
try
{
// Execute each validation rule
var isValid = engine.Evaluate(rule.Expression).AsBoolean();

if (!isValid)
{
result.Errors.Add(new CustomValidationError(
rule.Name,
rule.ErrorMessage ?? $"Validation rule '{rule.Name}' failed"
));
}
}
catch (Exception ex)
{
result.Errors.Add(new CustomValidationError(
rule.Name,
$"Error evaluating rule: {ex.Message}"
));
}
}

result.IsValid = !result.Errors.Any();
return Result.Ok(result);
}
catch (Exception ex)
{
return Result.Fail($"Validation failed: {ex.Message}");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Blocktrust.CredentialWorkflow.Core.Domain.ProcessFlow.Actions.Validation;
using FluentResults;
using MediatR;

namespace Blocktrust.CredentialWorkflow.Core.Commands.ValidateCredentials.CustomValidation;

public class CustomValidationRequest : IRequest<Result<CustomValidationResult>>
{
public object Data { get; }
public List<CustomValidationRule> Rules { get; }

public CustomValidationRequest(object data, List<CustomValidationRule> rules)
{
Data = data;
Rules = rules;
}
}

public class CustomValidationResult
{
public bool IsValid { get; set; }
public List<CustomValidationError> Errors { get; set; } = new();
}

public class CustomValidationError
{
public string RuleName { get; set; }
public string Message { get; set; }

public CustomValidationError(string ruleName, string message)
{
RuleName = ruleName;
Message = message;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
using System.Text.Json;
using Blocktrust.CredentialWorkflow.Core.Domain.ProcessFlow.Actions.Validation;
using FluentResults;
using MediatR;

namespace Blocktrust.CredentialWorkflow.Core.Commands.ValidateCredentials.W3cValidation;

public class W3cValidationHandler : IRequestHandler<W3cValidationRequest, Result<ValidationResult>>
{
public async Task<Result<ValidationResult>> Handle(W3cValidationRequest request, CancellationToken cancellationToken)
{
var result = new ValidationResult();
try
{
var credentialJson = JsonDocument.Parse(request.Credential);

foreach (var rule in request.Rules)
{
switch (rule.Type.ToLower())
{
case "required":
ValidateRequiredField(credentialJson, rule, result);
break;
case "format":
ValidateFormat(credentialJson, rule, result);
break;
case "range":
ValidateRange(credentialJson, rule, result);
break;
case "custom":
ValidateCustomRule(credentialJson, rule, result);
break;
}
}

result.IsValid = !result.Errors.Any();
return Result.Ok(result);
}
catch (JsonException ex)
{
return Result.Fail($"Invalid credential format: {ex.Message}");
}
catch (Exception ex)
{
return Result.Fail($"Validation failed: {ex.Message}");
}
}

private void ValidateRequiredField(JsonDocument credential, ValidationRule rule, ValidationResult result)
{
var path = rule.Configuration;
var pathParts = path.Split('.');
var element = credential.RootElement;

foreach (var part in pathParts)
{
if (!element.TryGetProperty(part, out var child))
{
result.Errors.Add(new ValidationError("Required", $"Required field '{path}' is missing"));
return;
}
element = child;
}
}

private void ValidateFormat(JsonDocument credential, ValidationRule rule, ValidationResult result)
{
var config = rule.Configuration.Split(':');
if (config.Length != 2)
{
result.Errors.Add(new ValidationError("Format", "Invalid format rule configuration"));
return;
}

var path = config[0];
var format = config[1];
var pathParts = path.Split('.');
var element = credential.RootElement;

foreach (var part in pathParts)
{
if (!element.TryGetProperty(part, out var child))
{
result.Errors.Add(new ValidationError("Format", $"Field '{path}' not found"));
return;
}
element = child;
}

// Validate format based on the format type
switch (format.ToUpper())
{
case "ISO8601":
if (!DateTime.TryParse(element.GetString(), out _))
{
result.Errors.Add(new ValidationError("Format", $"Field '{path}' is not a valid ISO8601 date"));
}
break;
// Add more format validations as needed
}
}

private void ValidateRange(JsonDocument credential, ValidationRule rule, ValidationResult result)
{
var config = rule.Configuration.Split(':');
if (config.Length != 2)
{
result.Errors.Add(new ValidationError("Range", "Invalid range rule configuration"));
return;
}

var path = config[0];
var range = config[1].Split('-');
if (range.Length != 2)
{
result.Errors.Add(new ValidationError("Range", "Invalid range format"));
return;
}

if (!decimal.TryParse(range[0], out var min) || !decimal.TryParse(range[1], out var max))
{
result.Errors.Add(new ValidationError("Range", "Invalid range values"));
return;
}

var pathParts = path.Split('.');
var element = credential.RootElement;

foreach (var part in pathParts)
{
if (!element.TryGetProperty(part, out var child))
{
result.Errors.Add(new ValidationError("Range", $"Field '{path}' not found"));
return;
}
element = child;
}

if (!decimal.TryParse(element.GetString(), out var value))
{
result.Errors.Add(new ValidationError("Range", $"Field '{path}' is not a valid number"));
return;
}

if (value < min || value > max)
{
result.Errors.Add(new ValidationError("Range", $"Field '{path}' value {value} is outside range {min}-{max}"));
}
}

private void ValidateCustomRule(JsonDocument credential, ValidationRule rule, ValidationResult result)
{
// Custom rule validation - can be extended based on requirements
// For now, just log that custom validation is not implemented
result.Errors.Add(new ValidationError("Custom", "Custom validation rules are not implemented"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Blocktrust.CredentialWorkflow.Core.Domain.ProcessFlow.Actions.Validation;
using FluentResults;
using MediatR;

namespace Blocktrust.CredentialWorkflow.Core.Commands.ValidateCredentials.W3cValidation;

public class W3cValidationRequest : IRequest<Result<ValidationResult>>
{
public string Credential { get; }
public List<ValidationRule> Rules { get; }

public W3cValidationRequest(string credential, List<ValidationRule> rules)
{
Credential = credential;
Rules = rules;
}
}

public class ValidationResult
{
public bool IsValid { get; set; }
public List<ValidationError> Errors { get; set; } = new();
}

public class ValidationError
{
public string RuleType { get; set; }
public string Message { get; set; }

public ValidationError(string ruleType, string message)
{
RuleType = ruleType;
Message = message;
}
}
Loading