Skip to content

Commit

Permalink
feat: add PGP extension project with file value processing capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
Stephane Royer committed Jan 16, 2025
1 parent d779259 commit e459b93
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/Paillave.Etl.Pgp/Paillave.Etl.Pgp.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\SharedSettings.props" />
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<PackageId>Paillave.EtlNet.Pgp</PackageId>
<PackageTags>ETL .net core SSIS reactive pgp</PackageTags>
<Product>ETL.net PGP extensions</Product>
<Description>Extensions for Etl.Net to handle PGP</Description>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Paillave.Etl\Paillave.Etl.csproj" />
</ItemGroup>
<ItemGroup>
</ItemGroup>
<ItemGroup>
<PackageReference Include="PgpCore" Version="6.5.1" />
</ItemGroup>
</Project>
34 changes: 34 additions & 0 deletions src/Paillave.Etl.Pgp/PgpFileValue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.IO;
using Paillave.Etl.Core;

namespace Paillave.Etl.Pgp
{
public class PgpFileValue<TMetadata> : FileValueBase<TMetadata> where TMetadata : IFileValueMetadata
{
private readonly Stream _stream;
private readonly IFileValue _underlyingFileValue;
public override string Name { get; }
public PgpFileValue(Stream stream, string name, TMetadata metadata, IFileValue underlyingFileValue)
: base(metadata)
=> (_stream, Name, _underlyingFileValue)
= (stream, name, underlyingFileValue);
public override Stream GetContent()
{
var ms = new MemoryStream();
_stream.Seek(0, SeekOrigin.Begin);
_stream.CopyTo(ms);
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
protected override void DeleteFile()
{
_underlyingFileValue.Delete();
}

public override StreamWithResource OpenContent()
{
_stream.Seek(0, SeekOrigin.Begin);
return new StreamWithResource(_stream);
}
}
}
153 changes: 153 additions & 0 deletions src/Paillave.Etl.Pgp/PgpFileValueProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Paillave.Etl.Core;
using PgpCore;

namespace Paillave.Etl.Pgp;
public enum PgpOperation
{
Encrypt,
EncryptAndSign,
Decrypt,
Sign,
UnSign,
Verify
}
public class PgpAdapterProcessorParameters
{
public PgpOperation Operation { get; set; } = PgpOperation.Decrypt;
public string? PrivateKey { get; set; }
public string? Passphrase { get; set; }
public string? PublicKey { get; set; }
public bool UseStreamCopy { get; set; } = true;
}
public class PgpFileValueMetadata : FileValueMetadataBase, IFileValueWithDestinationMetadata
{
public string ParentFileName { get; set; }
public IFileValueMetadata ParentFileMetadata { get; set; }
public Dictionary<string, IEnumerable<Destination>> Destinations { get; set; }
}
public class PgpFileValueProcessor : FileValueProcessorBase<PgpAdapterConnectionParameters, PgpAdapterProcessorParameters>
{
public PgpFileValueProcessor(string code, string name, string connectionName, PgpAdapterConnectionParameters connectionParameters, PgpAdapterProcessorParameters processorParameters)
: base(code, name, connectionName, connectionParameters, processorParameters) { }
public override ProcessImpact PerformanceImpact => ProcessImpact.Heavy;
public override ProcessImpact MemoryFootPrint => ProcessImpact.Average;
private EncryptionKeys CreateEncryptionKeys(PgpAdapterProcessorParameters processorParameters)
{
if (!string.IsNullOrWhiteSpace(processorParameters.Passphrase) && !string.IsNullOrWhiteSpace(processorParameters.PublicKey) && !string.IsNullOrWhiteSpace(processorParameters.PrivateKey))
return new EncryptionKeys(processorParameters.PublicKey, processorParameters.PrivateKey, processorParameters.Passphrase);
else if (!string.IsNullOrWhiteSpace(processorParameters.Passphrase) && !string.IsNullOrWhiteSpace(processorParameters.PrivateKey))
return new EncryptionKeys(processorParameters.PrivateKey, processorParameters.Passphrase);
else if (!string.IsNullOrWhiteSpace(processorParameters.PublicKey))
return new EncryptionKeys(processorParameters.PublicKey);
throw new ArgumentException("Missing key parameters");
}
protected override void Process(IFileValue fileValue, PgpAdapterConnectionParameters connectionParameters, PgpAdapterProcessorParameters processorParameters, Action<IFileValue> push, CancellationToken cancellationToken, IExecutionContext context)
{
var destinations = (fileValue.Metadata as IFileValueWithDestinationMetadata)?.Destinations;
if (cancellationToken.IsCancellationRequested) return;
using var inputStream = fileValue.Get(processorParameters.UseStreamCopy);

switch (processorParameters.Operation)
{
case PgpOperation.Decrypt:
{
var encryptionKeys = CreateEncryptionKeys(processorParameters);
var pgp = new PGP(encryptionKeys);
var ms = new MemoryStream();
pgp.Decrypt(inputStream, ms);
ms.Seek(0, SeekOrigin.Begin);
push(new PgpFileValue<PgpFileValueMetadata>(ms, fileValue.Name, new PgpFileValueMetadata
{
ParentFileName = fileValue.Name,
ParentFileMetadata = fileValue.Metadata,
Destinations = destinations
}, fileValue));
}
break;
case PgpOperation.Encrypt:
{
var encryptionKeys = CreateEncryptionKeys(processorParameters);
var pgp = new PGP(encryptionKeys);
var ms = new MemoryStream();
pgp.Encrypt(inputStream, ms);
ms.Seek(0, SeekOrigin.Begin);
push(new PgpFileValue<PgpFileValueMetadata>(ms, fileValue.Name, new PgpFileValueMetadata
{
ParentFileName = fileValue.Name,
ParentFileMetadata = fileValue.Metadata,
Destinations = destinations
}, fileValue));
}
break;
case PgpOperation.Sign:
{
var encryptionKeys = CreateEncryptionKeys(processorParameters);
var pgp = new PGP(encryptionKeys);
var ms = new MemoryStream();
pgp.Sign(inputStream, ms);
ms.Seek(0, SeekOrigin.Begin);
push(new PgpFileValue<PgpFileValueMetadata>(ms, fileValue.Name, new PgpFileValueMetadata
{
ParentFileName = fileValue.Name,
ParentFileMetadata = fileValue.Metadata,
Destinations = destinations
}, fileValue));
}
break;
case PgpOperation.EncryptAndSign:
{
var encryptionKeys = CreateEncryptionKeys(processorParameters);
var pgp = new PGP(encryptionKeys);
var ms = new MemoryStream();
pgp.EncryptAndSign(inputStream, ms);
ms.Seek(0, SeekOrigin.Begin);
push(new PgpFileValue<PgpFileValueMetadata>(ms, fileValue.Name, new PgpFileValueMetadata
{
ParentFileName = fileValue.Name,
ParentFileMetadata = fileValue.Metadata,
Destinations = destinations
}, fileValue));
}
break;
case PgpOperation.UnSign:
{
var encryptionKeys = CreateEncryptionKeys(processorParameters);
var pgp = new PGP(encryptionKeys);
var ms = new MemoryStream();
pgp.ClearSign(inputStream, ms);
ms.Seek(0, SeekOrigin.Begin);
push(new PgpFileValue<PgpFileValueMetadata>(ms, fileValue.Name, new PgpFileValueMetadata
{
ParentFileName = fileValue.Name,
ParentFileMetadata = fileValue.Metadata,
Destinations = destinations
}, fileValue));
}
break;
case PgpOperation.Verify:
{
var encryptionKeys = CreateEncryptionKeys(processorParameters);
var pgp = new PGP(encryptionKeys);
var ms = new MemoryStream();
var verified = pgp.Verify(inputStream, ms);
if (verified)
{
ms.Seek(0, SeekOrigin.Begin);
push(new PgpFileValue<PgpFileValueMetadata>(ms, fileValue.Name, new PgpFileValueMetadata
{
ParentFileName = fileValue.Name,
ParentFileMetadata = fileValue.Metadata,
Destinations = destinations
}, fileValue));
}
}
break;
}
}

protected override void Test(PgpAdapterConnectionParameters connectionParameters, PgpAdapterProcessorParameters processorParameters) { }
}
17 changes: 17 additions & 0 deletions src/Paillave.Etl.Pgp/PgpProviderProcessorAdapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Paillave.Etl.Core;

namespace Paillave.Etl.Pgp;

public class PgpAdapterConnectionParameters
{
}

public class PgpProviderProcessorAdapter : ProviderProcessorAdapterBase<PgpAdapterConnectionParameters, object, PgpAdapterProcessorParameters>
{
public override string Description => "Handle zip files";
public override string Name => "Zip";
protected override IFileValueProvider CreateProvider(string code, string name, string connectionName, PgpAdapterConnectionParameters connectionParameters, object inputParameters)
=> null;
protected override IFileValueProcessor CreateProcessor(string code, string name, string connectionName, PgpAdapterConnectionParameters connectionParameters, PgpAdapterProcessorParameters outputParameters)
=> new PgpFileValueProcessor(code, name, connectionName, connectionParameters, outputParameters);
}
14 changes: 14 additions & 0 deletions src/Paillave.Etl.sln
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Paillave.Etl.XmlFileTests",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Paillave.Etl.AzureStorageAccountFileProvider", "Paillave.Etl.AzureStorageAccountFileProvider\Paillave.Etl.AzureStorageAccountFileProvider.csproj", "{01C62EAC-96DF-488A-83AF-6CCA87A8F3CE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Paillave.Etl.Pgp", "Paillave.Etl.Pgp\Paillave.Etl.Pgp.csproj", "{98FCFFD8-5809-49B6-AEB6-1C1325A68584}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -390,6 +392,18 @@ Global
{01C62EAC-96DF-488A-83AF-6CCA87A8F3CE}.Release|x64.Build.0 = Release|Any CPU
{01C62EAC-96DF-488A-83AF-6CCA87A8F3CE}.Release|x86.ActiveCfg = Release|Any CPU
{01C62EAC-96DF-488A-83AF-6CCA87A8F3CE}.Release|x86.Build.0 = Release|Any CPU
{98FCFFD8-5809-49B6-AEB6-1C1325A68584}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{98FCFFD8-5809-49B6-AEB6-1C1325A68584}.Debug|Any CPU.Build.0 = Debug|Any CPU
{98FCFFD8-5809-49B6-AEB6-1C1325A68584}.Debug|x64.ActiveCfg = Debug|Any CPU
{98FCFFD8-5809-49B6-AEB6-1C1325A68584}.Debug|x64.Build.0 = Debug|Any CPU
{98FCFFD8-5809-49B6-AEB6-1C1325A68584}.Debug|x86.ActiveCfg = Debug|Any CPU
{98FCFFD8-5809-49B6-AEB6-1C1325A68584}.Debug|x86.Build.0 = Debug|Any CPU
{98FCFFD8-5809-49B6-AEB6-1C1325A68584}.Release|Any CPU.ActiveCfg = Release|Any CPU
{98FCFFD8-5809-49B6-AEB6-1C1325A68584}.Release|Any CPU.Build.0 = Release|Any CPU
{98FCFFD8-5809-49B6-AEB6-1C1325A68584}.Release|x64.ActiveCfg = Release|Any CPU
{98FCFFD8-5809-49B6-AEB6-1C1325A68584}.Release|x64.Build.0 = Release|Any CPU
{98FCFFD8-5809-49B6-AEB6-1C1325A68584}.Release|x86.ActiveCfg = Release|Any CPU
{98FCFFD8-5809-49B6-AEB6-1C1325A68584}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down

0 comments on commit e459b93

Please sign in to comment.