Skip to content

Commit

Permalink
Merge pull request #32 from bsandmann/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
ndigirigijohn authored Feb 24, 2025
2 parents 92f6e60 + eb26467 commit 7737e6a
Show file tree
Hide file tree
Showing 19 changed files with 2,134 additions and 161 deletions.
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

0 comments on commit 7737e6a

Please sign in to comment.