using System; using System.IO; using System.Security.Cryptography; using System.Threading.Tasks; using Elsa; using Elsa.ActivityResults; using Elsa.Attributes; using Elsa.Expressions; using Elsa.Providers.WorkflowStorage; using Elsa.Services; using Elsa.Services.Models; namespace DocumentManagement.Workflows.Activities { [Activity( Category = "Document Management", Description = "Saves a hash of the specified file onto the blockchain to prevent tampering." )] public class UpdateBlockchain : Activity { [ActivityInput( Label = "File", Hint = "The file to store its hash of onto the blockchain. Can be byte[] or Stream.", SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid}, DefaultWorkflowStorageProvider = TransientWorkflowStorageProvider.ProviderName )] public object File { get; set; } = default!; [ActivityOutput(Hint = "The computed file signature as stored on the blockchain.")] public string Output { get; set; } = default!; protected override async ValueTask OnExecuteAsync(ActivityExecutionContext context) { // Determine the type of File object: is it a Stream or a byte array? var bytes = File is Stream stream ? await stream.ReadBytesToEndAsync() : File is byte[] buffer ? buffer : throw new NotSupportedException(); // Compute hash. var fileSignature = ComputeSignature(bytes); // TODO: Schedule background work using Hangfire that will fake-update an imaginary blockchain with the file signature. // Suspend the workflow. return Suspend(); } protected override IActivityExecutionResult OnResume(ActivityExecutionContext context) { // When we resume, read the simply complete this activity. // TODO: Receive the computed file signature and set it as Output. return Done(); } private static string ComputeSignature(byte[] bytes) { using var algorithm = SHA256.Create(); var hashValue = algorithm.ComputeHash(bytes); return Convert.ToBase64String(hashValue); } } }