Contracts refactored

master
Inga 🏳‍🌈 7 years ago
parent 9f26b7241a
commit e942fdbd0c
  1. 11
      Source/Contracts/ContentTransformations/IContentEncryptor.cs
  2. 2
      Source/Contracts/ContentTransformations/IContentHasher.cs
  3. 11
      Source/Contracts/ContentTransformations/IContentTransformer.cs
  4. 13
      Source/Contracts/ReportStorage/IFileInfo.cs
  5. 21
      Source/Contracts/ReportStorage/IReportInfo.cs
  6. 18
      Source/Contracts/ReportStorage/IReportStorage.cs
  7. 13
      Source/Contracts/TargetBinaryStorage/IBlobInfo.cs
  8. 13
      Source/Contracts/TargetBinaryStorage/ITargetBinaryStorage.cs
  9. 13
      Source/Contracts/TargetMetadataStorage/ITargetDirectory.cs
  10. 10
      Source/Contracts/TargetMetadataStorage/ITargetFile.cs
  11. 15
      Source/Contracts/TargetMetadataStorage/ITargetFileVersion.cs
  12. 9
      Source/Contracts/TargetMetadataStorage/ITargetMetadataStorage.cs
  13. 13
      Source/Contracts/TargetMetadataStorage/ITargetMetadataStorageForRecovery.cs
  14. 13
      Source/Contracts/TargetStorage/ITargetDirectory.cs
  15. 18
      Source/Contracts/TargetStorage/ITargetFile.cs
  16. 9
      Source/Contracts/TargetStorage/ITargetStorage.cs
  17. 10
      Source/Contracts/TargetStorage/ITargetStorageForRecovery.cs
  18. 19
      Source/Encryptor.ClearText/ClearTextContentEncryptor.cs
  19. 3
      Source/Hasher.SHA1/SHA1ContentHasher.cs
  20. 8
      Tests/Encryptor.ClearText/EncryptorAndHasherTests.cs
  21. 14
      Tests/Hasher.SHA1/HasherTests.cs

@ -1,11 +0,0 @@
namespace EternalArrowBackup.Contracts.ContentTransformations
{
using System.Threading.Tasks;
public interface IContentEncryptor
{
Task<byte[]> Encrypt(byte[] originalData);
Task<IDecryptionResult> Decrypt(byte[] encryptedData);
}
}

@ -5,6 +5,6 @@
public interface IContentHasher public interface IContentHasher
{ {
Task<string> ComputeHash(byte[] content); Task<string> ComputeHash(Stream content);
} }
} }

@ -0,0 +1,11 @@
namespace EternalArrowBackup.Contracts.ContentTransformations
{
using System.Threading.Tasks;
public interface IContentTransformer
{
Task<byte[]> TransformData(byte[] originalData);
Task<IDecryptionResult> GetOriginalData(byte[] transformedData);
}
}

@ -0,0 +1,13 @@
namespace EternalArrowBackup.Contracts.ReportStorage
{
public interface IFileInfo
{
string DirectoryPath { get; }
string Filename { get; }
string Hash { get; }
long Size { get; }
}
}

@ -0,0 +1,21 @@
namespace EternalArrowBackup.Contracts.ReportStorage
{
using System;
public interface IReportInfo
{
string ReportId { get; }
DateTime DateTime { get; }
bool IsCompleted { get; }
bool IsEmpty { get; }
bool HasErrors { get; }
IObservable<string> GetAllErrors();
IObservable<IFileInfo> GetAllFiles();
}
}

@ -0,0 +1,18 @@
namespace EternalArrowBackup.Contracts.ReportStorage
{
using System;
using System.Threading.Tasks;
public interface IReportStorage
{
Task InitReport(string reportId);
Task CompleteReport(string reportId, bool isEmpty, bool hasErrors);
Task AddError(string reportId, string errorMessage);
Task AddFileInfo(string reportId, string directoryPath, string fileName, string hash, long size);
IObservable<IReportInfo> GetAllReports(bool includeEmpty);
}
}

@ -0,0 +1,13 @@
namespace EternalArrowBackup.Contracts.TargetBinaryStorage
{
using System;
public interface IBlobInfo
{
DateTime UploadDate { get; }
long OriginalSize { get; }
string[] BlockKeys { get; }
}
}

@ -0,0 +1,13 @@
namespace EternalArrowBackup.Contracts.TargetBinaryStorage
{
using System.Threading.Tasks;
public interface ITargetBinaryStorage
{
Task WriteBlock(byte[] block, string blobId, int partNumber, string blockKey);
Task WriteBlob(string blobId, long originalSize, string[] blockKeys);
Task<IBlobInfo> GetBlobIfExists(string blobId);
}
}

@ -0,0 +1,13 @@
namespace EternalArrowBackup.Contracts.TargetMetadataStorage
{
using System;
using System.Threading;
using System.Threading.Tasks;
public interface ITargetDirectory
{
Task UploadFile(string filename, string originalHash, long originalSize);
IObservable<ITargetFileVersion> GetAllLatestFileVersions(CancellationToken ct);
}
}

@ -0,0 +1,10 @@
namespace EternalArrowBackup.Contracts.TargetMetadataStorage
{
using System;
using System.Threading;
public interface ITargetFile
{
IObservable<ITargetFileVersion> GetAllVersions(CancellationToken ct);
}
}

@ -0,0 +1,15 @@
namespace EternalArrowBackup.Contracts.TargetMetadataStorage
{
using System;
public interface ITargetFileVersion
{
string Filename { get; }
string Hash { get; }
DateTime UploadDate { get; }
long Size { get; }
}
}

@ -0,0 +1,9 @@
namespace EternalArrowBackup.Contracts.TargetMetadataStorage
{
using System.Threading.Tasks;
public interface ITargetMetadataStorage
{
Task<ITargetDirectory> GetDirectory(string normalizedRelativeDirectoryPath);
}
}

@ -0,0 +1,13 @@
namespace EternalArrowBackup.Contracts.TargetMetadataStorage
{
using System;
using System.Threading;
using System.Threading.Tasks;
public interface ITargetMetadataStorageForRecovery
{
IObservable<ITargetDirectory> GetAllDirectories(CancellationToken ct);
Task<ITargetFile> GetFile(string normalizedRelativeDirectoryPath, string filename);
}
}

@ -1,13 +0,0 @@
namespace EternalArrowBackup.Contracts.TargetStorage
{
using System;
using System.Threading;
using System.Threading.Tasks;
public interface ITargetDirectory
{
Task UploadFile(string filename, byte[] data, string originalHash, long originalSize);
IObservable<ITargetFile> GetAllFiles(CancellationToken ct);
}
}

@ -1,18 +0,0 @@
namespace EternalArrowBackup.Contracts.TargetStorage
{
using System;
using System.Threading.Tasks;
public interface ITargetFile
{
string Filename { get; }
string Hash { get; }
DateTime UploadDate { get; }
long Size { get; }
Task<byte[]> RetrieveContents();
}
}

@ -1,9 +0,0 @@
namespace EternalArrowBackup.Contracts.TargetStorage
{
using System.Threading.Tasks;
public interface ITargetStorage
{
Task<ITargetDirectory> GetDirectory(string normalizedRelativePath);
}
}

@ -1,10 +0,0 @@
namespace EternalArrowBackup.Contracts.TargetStorage
{
using System;
using System.Threading;
public interface ITargetStorageForRecovery
{
IObservable<ITargetDirectory> GetAllDirectories(CancellationToken ct);
}
}

@ -1,11 +1,12 @@
namespace EternalArrowBackup.Encryptor.ClearText namespace EternalArrowBackup.Encryptor.ClearText
{ {
using System; using System;
using System.IO;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Contracts.ContentTransformations; using Contracts.ContentTransformations;
public class ClearTextContentEncryptor : IContentEncryptor public class ClearTextContentEncryptor : IContentTransformer
{ {
public ClearTextContentEncryptor(IContentHasher hasher) public ClearTextContentEncryptor(IContentHasher hasher)
{ {
@ -14,7 +15,7 @@
private IContentHasher Hasher { get; } private IContentHasher Hasher { get; }
public async Task<IDecryptionResult> Decrypt(byte[] encryptedData) public async Task<IDecryptionResult> GetOriginalData(byte[] encryptedData)
{ {
var hashLength = encryptedData[encryptedData.Length - 1]; var hashLength = encryptedData[encryptedData.Length - 1];
@ -25,19 +26,27 @@
Buffer.BlockCopy(encryptedData, originalData.Length, hashBytes, 0, hashBytes.Length); Buffer.BlockCopy(encryptedData, originalData.Length, hashBytes, 0, hashBytes.Length);
var expectedHash = Encoding.UTF8.GetString(hashBytes); var expectedHash = Encoding.UTF8.GetString(hashBytes);
var actualHash = await this.Hasher.ComputeHash(originalData); using (var stream = new MemoryStream(originalData))
{
var actualHash = await this.Hasher.ComputeHash(stream);
if (expectedHash != actualHash) if (expectedHash != actualHash)
{ {
return new FailedDecryptionResult(); return new FailedDecryptionResult();
} }
}
return new SuccessfulDecryptionResult(originalData); return new SuccessfulDecryptionResult(originalData);
} }
public async Task<byte[]> Encrypt(byte[] originalData) public async Task<byte[]> TransformData(byte[] originalData)
{
string hash;
using (var stream = new MemoryStream(originalData))
{ {
var hash = await this.Hasher.ComputeHash(originalData); hash = await this.Hasher.ComputeHash(stream);
}
var hashBytes = Encoding.UTF8.GetBytes(hash); var hashBytes = Encoding.UTF8.GetBytes(hash);
if (hashBytes.Length >= 256) if (hashBytes.Length >= 256)
{ {

@ -1,12 +1,13 @@
namespace EternalArrowBackup.Hasher.SHA1 namespace EternalArrowBackup.Hasher.SHA1
{ {
using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Contracts.ContentTransformations; using Contracts.ContentTransformations;
public class SHA1ContentHasher : IContentHasher public class SHA1ContentHasher : IContentHasher
{ {
public Task<string> ComputeHash(byte[] content) public Task<string> ComputeHash(Stream content)
{ {
return Task.Run(() => return Task.Run(() =>
{ {

@ -16,19 +16,19 @@
var messageBytes = Encoding.ASCII.GetBytes(message); var messageBytes = Encoding.ASCII.GetBytes(message);
var hasher = new SHA1ContentHasher(); var hasher = new SHA1ContentHasher();
var encryptor = new ClearTextContentEncryptor(hasher); var encryptor = new ClearTextContentEncryptor(hasher);
var encrypted = await encryptor.Encrypt(messageBytes); var encrypted = await encryptor.TransformData(messageBytes);
var decryptionResult = await encryptor.Decrypt(encrypted); var decryptionResult = await encryptor.GetOriginalData(encrypted);
Assert.True(decryptionResult.IsSuccessful); Assert.True(decryptionResult.IsSuccessful);
Assert.Equal(messageBytes, decryptionResult.Data); Assert.Equal(messageBytes, decryptionResult.Data);
encrypted[0]++; encrypted[0]++;
decryptionResult = await encryptor.Decrypt(encrypted); decryptionResult = await encryptor.GetOriginalData(encrypted);
Assert.False(decryptionResult.IsSuccessful); Assert.False(decryptionResult.IsSuccessful);
encrypted[0]--; encrypted[0]--;
encrypted[encrypted.Length - 1]--; encrypted[encrypted.Length - 1]--;
decryptionResult = await encryptor.Decrypt(encrypted); decryptionResult = await encryptor.GetOriginalData(encrypted);
Assert.False(decryptionResult.IsSuccessful); Assert.False(decryptionResult.IsSuccessful);
} }
} }

@ -2,6 +2,7 @@
{ {
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Xunit; using Xunit;
@ -21,9 +22,12 @@
var expectedHashFormatted = expectedHash.Replace(" ", string.Empty).ToLowerInvariant(); var expectedHashFormatted = expectedHash.Replace(" ", string.Empty).ToLowerInvariant();
var hasher = new SHA1ContentHasher(); var hasher = new SHA1ContentHasher();
var messageBytes = Encoding.ASCII.GetBytes(inputMessage); var messageBytes = Encoding.ASCII.GetBytes(inputMessage);
var actualHash = await hasher.ComputeHash(messageBytes); using (var stream = new MemoryStream(messageBytes))
{
var actualHash = await hasher.ComputeHash(stream);
Assert.Equal(expectedHashFormatted, actualHash); Assert.Equal(expectedHashFormatted, actualHash);
} }
}
// Single-threaded SHA1 performance on i5-6500 is around 500MB/s // Single-threaded SHA1 performance on i5-6500 is around 500MB/s
[Theory] [Theory]
@ -46,12 +50,16 @@
var expectedTimeHigh = 1 + length / (MegabytesPerSecondLowSpeed * 1000); var expectedTimeHigh = 1 + length / (MegabytesPerSecondLowSpeed * 1000);
var hasher = new SHA1ContentHasher(); var hasher = new SHA1ContentHasher();
using (var stream = new MemoryStream(messageBytes))
{
await hasher.ComputeHash(stream);
stream.Seek(0, SeekOrigin.Begin);
var stopwatch = new Stopwatch(); var stopwatch = new Stopwatch();
stopwatch.Start(); stopwatch.Start();
await hasher.ComputeHash(messageBytes); await hasher.ComputeHash(stream);
stopwatch.Stop(); stopwatch.Stop();
Assert.InRange(stopwatch.ElapsedMilliseconds, expectedTimeLow, expectedTimeHigh); Assert.InRange(stopwatch.ElapsedMilliseconds, expectedTimeLow, expectedTimeHigh);
} }
} }
} }
}

Loading…
Cancel
Save