jj: Add filecontainer
This commit is contained in:
284
Filesystem/FileContainer.vb
Normal file
284
Filesystem/FileContainer.vb
Normal file
@@ -0,0 +1,284 @@
|
||||
Imports System.IO
|
||||
Imports System.Runtime.Serialization.Formatters.Binary
|
||||
Imports DigitalData.Modules.Logging
|
||||
|
||||
''' <module>FileContainer</module>
|
||||
''' <version>0.0.0.1</version>
|
||||
''' <date>16.11.2018</date>
|
||||
''' <summary>
|
||||
''' File Container for securely saving files
|
||||
''' </summary>
|
||||
''' <dependencies>
|
||||
''' NLog, >= 4.5.8
|
||||
''' </dependencies>
|
||||
''' <params>
|
||||
''' LogConfig, DigitalData.Module.Logging.LogConfig
|
||||
''' A LogConfig object
|
||||
''' </params>
|
||||
''' <props>
|
||||
''' </props>
|
||||
''' <example>
|
||||
''' </example>
|
||||
''' <remarks>
|
||||
''' </remarks>
|
||||
Public Class FileContainer
|
||||
Private _files As List(Of FileEntry)
|
||||
Private _crypto As Encryption
|
||||
Private _compression As Compression
|
||||
Private _formatter As BinaryFormatter
|
||||
Private _containerId As Guid
|
||||
Private _inner As FileContainerInner
|
||||
Private _logger As Logger
|
||||
Private _logConfig As LogConfig
|
||||
|
||||
<Serializable>
|
||||
Public Class FileEntry
|
||||
Public FileId As String
|
||||
Public Contents As Byte()
|
||||
Public CreatedAt As DateTime
|
||||
Public UpdatedAt As DateTime
|
||||
End Class
|
||||
|
||||
<Serializable>
|
||||
Public Class FileContainerInner
|
||||
Public Files As List(Of FileEntry)
|
||||
Public ContainerID As Guid
|
||||
Public CreatedAt As DateTime
|
||||
Public UpdatedAt As DateTime
|
||||
End Class
|
||||
|
||||
Public ReadOnly Property ContainerId As String
|
||||
Get
|
||||
If _inner Is Nothing Then
|
||||
Return Nothing
|
||||
End If
|
||||
|
||||
Return _inner.ContainerID.ToString
|
||||
End Get
|
||||
End Property
|
||||
|
||||
|
||||
''' <summary>
|
||||
''' Gibt eine Auflistung der Dateien in Container zurück.
|
||||
''' </summary>
|
||||
''' <returns>Eine Liste von Objekten der Klasse FileContainer.FileEntry</returns>
|
||||
Public ReadOnly Property Files As List(Of FileEntry)
|
||||
Get
|
||||
If _inner Is Nothing Then
|
||||
Return Nothing
|
||||
End If
|
||||
|
||||
Return _inner.Files
|
||||
End Get
|
||||
End Property
|
||||
|
||||
''' <summary>
|
||||
''' Erstellt eine Representation eines Datei Containers, der mit dem angegebenen Passwort geschützt ist.
|
||||
''' Ist für das speichern von neuen Containern und für das laden vorhandener Container nötig.
|
||||
''' </summary>
|
||||
''' <param name="Password">Das Passwort, mit dem der Container ver- und entschlüsselt wird</param>
|
||||
''' <example>
|
||||
''' Dim password = "meinpasswort"
|
||||
''' Dim container = new FileContainer(password)
|
||||
''' </example>
|
||||
Public Sub New(LogConfig As LogConfig, Password As String)
|
||||
_logger = LogConfig.GetLogger()
|
||||
_crypto = New Encryption(LogConfig, Password)
|
||||
_compression = New Compression(LogConfig)
|
||||
_formatter = New BinaryFormatter
|
||||
_inner = New FileContainerInner() With {
|
||||
.Files = New List(Of FileEntry),
|
||||
.ContainerID = Guid.NewGuid(),
|
||||
.CreatedAt = New DateTime()
|
||||
}
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Speichert einen Datei Container am angegebenen Pfad.
|
||||
''' Davor werden die Dateien in Files komprimiert und dann verschlüsselt.
|
||||
''' </summary>
|
||||
''' <param name="Path">Der Pfad mit Dateiname, unter dem der Container abgelegt wird.</param>
|
||||
''' <see cref="Files"/>
|
||||
''' <example>
|
||||
''' container.AddFile("datei1.txt")
|
||||
''' container.AddFile("datei2.pdf")
|
||||
''' container.Save("container.enc")
|
||||
''' </example>
|
||||
Public Sub Save(Path As String)
|
||||
Try
|
||||
' 1. Serialize
|
||||
Dim oFileContainerInner As Byte() = Serialize(_inner)
|
||||
' 2. Compress
|
||||
Dim oFileContainerCompressed As Byte() = _compression.Compress(oFileContainerInner)
|
||||
' 3. Encrypt
|
||||
Dim oFileContainerEncrypted As Byte() = _crypto.Encrypt(oFileContainerCompressed)
|
||||
|
||||
BytesToFile(oFileContainerEncrypted, Path)
|
||||
Catch ex As Exception
|
||||
_logger.Error(ex)
|
||||
Throw ex
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Speichert einen Datei Container am angegebenen Pfad.
|
||||
''' Davor werden die Dateien in Files komprimiert und dann verschlüsselt.
|
||||
''' </summary>
|
||||
''' <param name="Path">Der Pfad mit Dateiname, unter dem der Container abgelegt wird.</param>
|
||||
''' <example>
|
||||
''' Public Async Sub foobar()
|
||||
''' ...
|
||||
''' container.AddFile("datei1.txt")
|
||||
''' container.AddFile("datei2.pdf")
|
||||
''' await container.SaveAsync("container.enc")
|
||||
''' ...
|
||||
''' End Sub
|
||||
''' </example>
|
||||
Public Async Function SaveAsync(Path As String) As Task
|
||||
Try
|
||||
' 1. Serialize
|
||||
Dim oFileContainerInner As Byte() = Serialize(_inner)
|
||||
' 2. Compress
|
||||
Dim oFileContainerCompressed As Byte() = Await _compression.CompressAsync(oFileContainerInner)
|
||||
'Dim bFilesCompressed = bFiles
|
||||
' 3. Encrypt
|
||||
Dim oFileContainerEncrypted As Byte() = Await _crypto.EncryptAsync(oFileContainerCompressed)
|
||||
|
||||
BytesToFileAsync(oFileContainerEncrypted, Path)
|
||||
Catch ex As Exception
|
||||
_logger.Error(ex)
|
||||
Throw ex
|
||||
End Try
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Lädt einen Datei Container aus dem angegebenen Pfad.
|
||||
''' Anschließend werden die enthaltenen Dateien entschlüsselt, dekomprimiert und in Files abgelegt.
|
||||
''' </summary>
|
||||
''' <param name="Path">Der Pfad mit Dateiname, von dem der Container geladen wird.</param>
|
||||
''' <see cref="Files"/>
|
||||
''' <example>
|
||||
''' container.Load("container.enc")
|
||||
''' Dim files As List(Of FileContainer.FileEntry) = container.Files
|
||||
''' </example>
|
||||
Public Sub Load(Path As String)
|
||||
Try
|
||||
Dim oContainerInnerEncrypted As Byte() = FileToBytes(Path)
|
||||
|
||||
' 1. Decrypt
|
||||
Dim oFileContainerCompressed As Byte() = _crypto.Decrypt(oContainerInnerEncrypted)
|
||||
' 2. Decompress
|
||||
Dim oFileContainerInner As Byte() = _compression.Decompress(oFileContainerCompressed)
|
||||
' 3. Deserialize
|
||||
|
||||
_inner = Deserialize(oFileContainerInner)
|
||||
Catch ex As Exception
|
||||
_logger.Error(ex)
|
||||
Throw ex
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Lädt einen Datei Container aus dem angegebenen Pfad.
|
||||
''' Anschließend werden die enthaltenen Dateien entschlüsselt, dekomprimiert und in Files abgelegt.
|
||||
''' </summary>
|
||||
''' <param name="Path">Der Pfad mit Dateiname, von dem der Container geladen wird.</param>
|
||||
''' <example>
|
||||
''' Public Async Sub foobar()
|
||||
''' ...
|
||||
''' await container.LoadAsync("container.enc")
|
||||
''' Dim files As List(Of FileContainer.FileEntry) = container.Files
|
||||
''' ...
|
||||
''' End Sub
|
||||
''' </example>
|
||||
Public Async Function LoadAsync(Path As String) As Task
|
||||
Try
|
||||
Dim oContainerInnerEncrypted As Byte() = Await FileToBytesAsync(Path)
|
||||
|
||||
' 1. Decrypt
|
||||
Dim oFileContainerCompressed As Byte() = Await _crypto.DecryptAsync(oContainerInnerEncrypted)
|
||||
' 2. Decompress
|
||||
Dim oFileContainerInner As Byte() = Await _compression.DecompressAsync(oFileContainerCompressed)
|
||||
' 3. Deserialize
|
||||
_inner = Deserialize(oFileContainerInner)
|
||||
Catch ex As Exception
|
||||
_logger.Error(ex)
|
||||
Throw ex
|
||||
End Try
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Fügt einem Datei Container eine neue Datei hinzu
|
||||
''' </summary>
|
||||
''' <param name="FilePath">Der Pfad zur Datei, die im Container gespeichert werden soll</param>
|
||||
''' <exception cref="FileNotFoundException" />
|
||||
Public Sub AddFile(FilePath As String)
|
||||
Try
|
||||
Dim oFileInfo As New FileInfo(FilePath)
|
||||
|
||||
If oFileInfo.Exists = False Then
|
||||
Throw New FileNotFoundException($"{FilePath} is not a valid path.")
|
||||
End If
|
||||
|
||||
AddFile(IO.File.ReadAllBytes(FilePath))
|
||||
Catch ex As Exception
|
||||
_logger.Error(ex)
|
||||
Throw ex
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
Public Sub AddFile(FileContents As Byte())
|
||||
Try
|
||||
Dim oFileEntry As New FileEntry With {
|
||||
.Contents = FileContents,
|
||||
.FileId = Guid.NewGuid().ToString()
|
||||
}
|
||||
|
||||
_inner.Files.Add(oFileEntry)
|
||||
Catch ex As Exception
|
||||
_logger.Error(ex)
|
||||
Throw ex
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
Public Function GetFile(FileId As String) As FileEntry
|
||||
Return _inner.Files.Where(Function(f) f.FileId = FileId).FirstOrDefault()
|
||||
End Function
|
||||
|
||||
Private Function Serialize(InnerData As FileContainerInner) As Byte()
|
||||
Using oStream As New MemoryStream
|
||||
_formatter.Serialize(oStream, InnerData)
|
||||
Return oStream.ToArray()
|
||||
End Using
|
||||
End Function
|
||||
|
||||
Private Function Deserialize(InnerData As Byte()) As FileContainerInner
|
||||
Using oStream As New MemoryStream(InnerData)
|
||||
Dim oInner = TryCast(_formatter.Deserialize(oStream), FileContainerInner)
|
||||
Return oInner
|
||||
End Using
|
||||
End Function
|
||||
|
||||
Private Sub BytesToFile(Data As Byte(), FilePath As String)
|
||||
IO.File.WriteAllBytes(FilePath, Data)
|
||||
End Sub
|
||||
|
||||
Private Function FileToBytes(FilePath As String) As Byte()
|
||||
Return IO.File.ReadAllBytes(FilePath)
|
||||
End Function
|
||||
|
||||
Private Async Function FileToBytesAsync(FilePath As String) As Task(Of Byte())
|
||||
Using oFileStream = New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, True)
|
||||
Dim oBuffer As Byte() = New Byte(oFileStream.Length - 1) {}
|
||||
Await oFileStream.ReadAsync(oBuffer, 0, oFileStream.Length)
|
||||
oFileStream.Close()
|
||||
Return oBuffer
|
||||
End Using
|
||||
End Function
|
||||
|
||||
Private Async Sub BytesToFileAsync(Data As Byte(), FilePath As String)
|
||||
Using oSourceStream As New FileStream(FilePath, FileMode.Append, FileAccess.Write, FileShare.None, bufferSize:=4096, useAsync:=True)
|
||||
Await oSourceStream.WriteAsync(Data, 0, Data.Length)
|
||||
End Using
|
||||
End Sub
|
||||
End Class
|
||||
Reference in New Issue
Block a user