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

POC for encrypted support packages #469

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion src/Orc.SupportPackage.Example/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ protected override void OnStartup(StartupEventArgs e)
base.OnStartup(e);
}
}
}
}
99 changes: 94 additions & 5 deletions src/Orc.SupportPackage.Example/ViewModels/MainViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using SystemInfo;
using Catel;
using Catel.IoC;
using Catel.MVVM;
using Catel.Services;
using Catel.Threading;
using Orc.FileSystem;
using Orc.SupportPackage.ViewModels;
using SystemInfo;

public class MainViewModel : ViewModelBase
{
Expand All @@ -21,27 +23,49 @@ public class MainViewModel : ViewModelBase

private readonly IScreenCaptureService _screenCaptureService;
private readonly ISystemInfoService _systemInfoService;
private readonly IMessageService _messageService;
private readonly IUIVisualizerService _uiVisualizerService;
private readonly IAppDataService _appDataService;

public MainViewModel(IScreenCaptureService screenCaptureService, ISystemInfoService systemInfoService,
IUIVisualizerService uiVisualizerService, IAppDataService appDataService)
private readonly ITypeFactory _typeFactory;
private readonly IEncryptionService _encryptionService;
private readonly IOpenFileService _openFileService;
private readonly IFileService _fileService;

public MainViewModel(IScreenCaptureService screenCaptureService, ISystemInfoService systemInfoService, IMessageService messageService,
IUIVisualizerService uiVisualizerService, IAppDataService appDataService, ITypeFactory typeFactory, IEncryptionService encryptionService,
IOpenFileService openFileService, IFileService fileService)
{
Argument.IsNotNull(() => screenCaptureService);
Argument.IsNotNull(() => systemInfoService);
Argument.IsNotNull(() => messageService);
Argument.IsNotNull(() => uiVisualizerService);
Argument.IsNotNull(() => appDataService);
Argument.IsNotNull(() => typeFactory);
Argument.IsNotNull(() => encryptionService);
Argument.IsNotNull(() => openFileService);
Argument.IsNotNull(() => fileService);

_screenCaptureService = screenCaptureService;
_systemInfoService = systemInfoService;
_messageService = messageService;
_uiVisualizerService = uiVisualizerService;
_appDataService = appDataService;

_typeFactory = typeFactory;
_encryptionService = encryptionService;
_openFileService = openFileService;
_fileService = fileService;
Screenshot = new TaskCommand(OnScreenshotExecuteAsync);
ShowSystemInfo = new TaskCommand(OnShowSystemInfoExecuteAsync);
SavePackage = new TaskCommand(OnSavePackageExecuteAsync);
EncryptAndSavePackage = new TaskCommand(OnEncryptAndSavePackageExecuteAsync);
GenerateKeys = new TaskCommand(OnGenerateKeysExecuteAsync);
DecryptPackage = new TaskCommand(OnDecryptPackageExecuteAsync);

Title = "Orc.SupportPackage example";

var currentDirectory = Environment.CurrentDirectory;
PublicKeyPath = Path.Combine(currentDirectory, "public.pem");
PrivateKeyPath = Path.Combine(currentDirectory, "private.pem");
}

#region Commands
Expand All @@ -52,6 +76,66 @@ private async Task OnSavePackageExecuteAsync()
await _uiVisualizerService.ShowDialogAsync<SupportPackageViewModel>();
}

public TaskCommand EncryptAndSavePackage { get; private set; }

private async Task OnEncryptAndSavePackageExecuteAsync()
{
var supportPackageViewModel = _typeFactory.CreateInstance<SupportPackageViewModel>();
supportPackageViewModel.EncryptionContext = new EncryptionContext
{
PrivateKeyPath = PrivateKeyPath,
PublicKey = await _encryptionService.ReadPublicKeyFromPemFileAsync(PublicKeyPath)
};

await _uiVisualizerService.ShowDialogAsync(supportPackageViewModel);
}

public TaskCommand GenerateKeys { get; private set; }

private async Task OnGenerateKeysExecuteAsync()
{
_encryptionService.Generate(PrivateKeyPath, PublicKeyPath);
await _messageService.ShowInformationAsync("Encryption keys generated");
}

public TaskCommand DecryptPackage { get; private set; }

private async Task OnDecryptPackageExecuteAsync()
{
var result = await _openFileService.DetermineFileAsync(new DetermineOpenFileContext
{
});

if (!result.Result)
{
return;
}

var directory = Path.GetDirectoryName(result.FileName);
var fileName = Path.GetFileNameWithoutExtension(result.FileName);

var decryptedPackagePath = Path.Combine(directory, $"{fileName}_dec.spkg");

using (var sourceStream = _fileService.OpenRead(result.FileName))
{
if (_fileService.Exists(decryptedPackagePath))
{
_fileService.Delete(decryptedPackagePath);
}

using (var targetStream = _fileService.Create(decryptedPackagePath))
{
await _encryptionService.DecryptAsync(sourceStream, targetStream, new EncryptionContext
{
PrivateKeyPath = PrivateKeyPath,
PublicKey = await _encryptionService.ReadPublicKeyFromPemFileAsync(PublicKeyPath)
});
}
}

await _messageService.ShowInformationAsync($"Decrypted support package saved on path {decryptedPackagePath}");
}

public TaskCommand Screenshot { get; private set; }

private async Task OnScreenshotExecuteAsync()
Expand Down Expand Up @@ -85,12 +169,17 @@ private async Task OnShowSystemInfoExecuteAsync()
var sysInfoLines = sysInfoElements.Select(x => x.ToString());
SystemInfo = string.Join("\n", sysInfoLines);
}

#endregion

#region Properties
public BitmapImage ScreenPic { get; private set; }

public string SystemInfo { get; set; }

public string PrivateKeyPath { get; set; }

public string PublicKeyPath { get; set; }
#endregion
}
}
50 changes: 49 additions & 1 deletion src/Orc.SupportPackage.Example/Views/MainView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,55 @@

<TabItem Header="Zipping all data">
<Grid>
<Button Content="Save support package as" Margin="15 15 15 15" Command="{Binding SavePackage}"/>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>

<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<Label>Public Key</Label>
<Label Grid.Row="1">Private Key</Label>
<TextBox Grid.Column="1"
Margin="4"
Text="{Binding PublicKeyPath}"/>
<TextBox Grid.Column="1"
Margin="4"
Grid.Row="1"
Text="{Binding PrivateKeyPath}"/>

<Button Grid.RowSpan="2"
Grid.Column="2"
Margin="4"
Padding="6"
Command="{Binding GenerateKeys}">
Generate
</Button>

<Button Content="Save support package as"
Margin="15"
Grid.ColumnSpan="3"
Grid.Row="2"
Command="{Binding SavePackage}"/>

<Button Content="Save encrypted support package as"
Margin="15"
Grid.ColumnSpan="3"
Grid.Row="3"
Command="{Binding EncryptAndSavePackage}"/>

<Button Content="Decrypt support package"
Margin="15"
Grid.ColumnSpan="3"
Grid.Row="4"
Command="{Binding DecryptPackage}"/>
</Grid>
</TabItem>
</TabControl>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Orc.SupportPackage
{
using System.Collections.Generic;

public class SupportPackageBuilderContext
{
/// <summary>
/// Name of support package file
/// </summary>
public string FileName { get; set; }

public List<SupportPackageFileSystemArtifact> Artifacts { get; set; }

public bool IsEncrypted { get; set; }

public EncryptionContext EncryptionContext { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public interface ISupportPackageBuilderService
{
#region Methods
Task<bool> CreateSupportPackageAsync(string fileName, List<SupportPackageFileSystemArtifact> artifacts);
Task<bool> CreateSupportPackageAsync(SupportPackageBuilderContext context);

#endregion
}
}
}
110 changes: 34 additions & 76 deletions src/Orc.SupportPackage.Xaml/Services/SupportPackageBuilderService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@

namespace Orc.SupportPackage
{
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
Expand All @@ -20,8 +17,6 @@ namespace Orc.SupportPackage

public class SupportPackageBuilderService : ISupportPackageBuilderService
{
private const int DirectorySizeLimitInBytes = 25 * 1024 * 1024;

#region Fields
private static readonly ILog Log = LogManager.GetCurrentClassLogger();

Expand All @@ -45,6 +40,18 @@ public SupportPackageBuilderService(ISupportPackageService supportPackageService
#region Methods
public virtual async Task<bool> CreateSupportPackageAsync(string fileName, List<SupportPackageFileSystemArtifact> artifacts)
{
return await CreateSupportPackageAsync(new SupportPackageBuilderContext
{
FileName = fileName,
Artifacts = artifacts,
});
}

public async Task<bool> CreateSupportPackageAsync(SupportPackageBuilderContext context)
{
var fileName = context.FileName;
var artifacts = context.Artifacts;

Argument.IsNotNullOrWhitespace(() => fileName);
Argument.IsNotNull(() => artifacts);

Expand All @@ -61,7 +68,9 @@ public virtual async Task<bool> CreateSupportPackageAsync(string fileName, List<
}

var excludeFileNamePatterns = artifacts.Where(artifact => !artifact.IncludeInSupportPackage).OfType<SupportPackageFileNamePattern>().SelectMany(artifact => artifact.FileNamePatterns).Distinct().ToArray();
var directories = artifacts.Where(artifact => artifact.IncludeInSupportPackage).OfType<SupportPackageDirectory>().Select(artifact => artifact.DirectoryName).Distinct().ToArray();
var directories = artifacts.Where(artifact => artifact.IncludeInSupportPackage).OfType<SupportPackageDirectory>().Select(artifact => artifact.DirectoryName)
.Distinct()
.ToArray();

builder.AppendLine();
builder.AppendLine("## Exclude file name patterns");
Expand All @@ -81,79 +90,28 @@ public virtual async Task<bool> CreateSupportPackageAsync(string fileName, List<
builder.AppendLine("- " + directory);
}

var result = await _supportPackageService.CreateSupportPackageAsync(fileName, directories, excludeFileNamePatterns);

var customDataDirectoryName = "CustomData";
using (var fileStream = new FileStream(fileName, FileMode.OpenOrCreate))
var customData = artifacts.Where(artifact => artifact.IncludeInSupportPackage).OfType<CustomPathsPackageFileSystemArtifact>().SelectMany(x => x.Paths);
if (customData.Any())
{
using (var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Update))
{
foreach (var artifact in artifacts.OfType<CustomPathsPackageFileSystemArtifact>().Where(artifact => artifact.IncludeInSupportPackage))
{
builder.AppendLine();
builder.AppendLine("## Include custom data");
builder.AppendLine();

foreach (var path in artifact.Paths)
{
try
{
var directoryInfo = new DirectoryInfo(path);
if (directoryInfo.Exists)
{
var directorySize = directoryInfo.GetFiles("*.*", SearchOption.AllDirectories).Sum(info => info.Length);
if (directorySize > DirectorySizeLimitInBytes)
{
Log.Info("Skipped directory '{0}' beacuse its size is greater than '{1}' bytes", path, DirectorySizeLimitInBytes);

builder.AppendLine("- Directory (skipped): " + path);
}
else
{
zipArchive.CreateEntryFromDirectory(path, Path.Combine(customDataDirectoryName, directoryInfo.Name), CompressionLevel.Optimal);
builder.AppendLine("- Directory: " + path);
}
}
}
catch (Exception ex)
{
Log.Warning(ex);
}

try
{
if (_fileService.Exists(path))
{
zipArchive.CreateEntryFromAny(path, customDataDirectoryName, CompressionLevel.Optimal);
builder.AppendLine("- File: " + path);
}
}
catch (Exception ex)
{
Log.Warning(ex);
}
}
}

builder.AppendLine();
builder.AppendLine("## File system entries");
builder.AppendLine();
builder.AppendLine("- Total: " + zipArchive.Entries.Count);
builder.AppendLine("- Files: " + zipArchive.Entries.Count(entry => !entry.Name.EndsWith("/")));
builder.AppendLine("- Directories: " + zipArchive.Entries.Count(entry => entry.Name.EndsWith("/")));

var builderEntry = zipArchive.CreateEntry("SupportPackageOptions.txt");

using (var streamWriter = new StreamWriter(builderEntry.Open()))
{
await streamWriter.WriteAsync(builder.ToString());
}

await fileStream.FlushAsync();
}
builder.AppendLine();
builder.AppendLine("## Include custom data");
builder.AppendLine();
}

return result;
using (var supportPackageContext = new SupportPackageContext())
{
supportPackageContext.ZipFileName = fileName;
supportPackageContext.AddArtifactDirectories(directories);
supportPackageContext.AddExcludeFileNamePatterns(excludeFileNamePatterns);
supportPackageContext.AddCustomFileSystemPaths(customData.ToArray());
supportPackageContext.DescriptionBuilder = builder;
supportPackageContext.IsEncrypted = context.IsEncrypted;
supportPackageContext.EncryptionContext = context.EncryptionContext;

var result = await _supportPackageService.CreateSupportPackageAsync(supportPackageContext);

return result;
}
}

#endregion
Expand Down
Loading