Imports DigitalData.Modules.Base Imports DigitalData.Modules.Database Imports DigitalData.Modules.Jobs.Exceptions Imports DigitalData.Modules.Logging Imports System.Data Imports System.IO Imports System.Security.Cryptography Public Class HashFunctions Inherits BaseClass Private ReadOnly Database As MSSQLServer Public Sub New(pLogConfig As LogConfig, pDatabase As MSSQLServer) MyBase.New(pLogConfig) Database = pDatabase End Sub ''' ''' Generates the MD5 Checksum of a file and checks it against the histroy table TBEDM_ZUGFERD_HISTORY_IN ''' ''' The path of the file to be checked ''' Should the check take into account the rejection status of the file? ''' The MD5 Checksum of the file, or an empty string, if the Checksum could not be created ''' Throws, when the file should be rejected, ie. if it already exists in the table Public Function GenerateAndCheck_MD5Sum(pFile As FileInfo, pMessageId As String, pIgnoreRejectionStatus As Boolean) As String Dim oMD5CheckSum = CreateMD5(pFile.FullName) ' Exit if MD5 could not be created If oMD5CheckSum = String.Empty Then Logger.Warn("MD5 Checksum is nothing for file [{0}]!", pFile.FullName) Return oMD5CheckSum End If ' Check if Checksum exists in History Table Dim oCheckCommand = $"SELECT * FROM TBEMLP_HISTORY WHERE GUID = (SELECT MAX(GUID) FROM TBEMLP_HISTORY WHERE UPPER(MD5HASH) = UPPER('{oMD5CheckSum}'))" Dim oTable As DataTable = Database.GetDatatable(oCheckCommand, MSSQLServer.TransactionMode.NoTransaction) ' If History entries could not be fetched, just return the MD5 Checksum If IsNothing(oTable) Then Logger.Warn("Be careful: oExistsDT is nothing for file [{0}]!", pFile.FullName) Return oMD5CheckSum End If ' If Checksum does not exist in History entries, just return the MD5 Checksum If oTable.Rows.Count = 0 Then Logger.Debug("File [{0}] was not found in History!", pFile.FullName) Return oMD5CheckSum End If ' ==================================================== ' Checksum exists in History entries, reject! ' ==================================================== Dim oRejected As Boolean Dim oHistoryId As Integer ' Try to read Rejected Status and History Id Try Dim oRow As DataRow = oTable.Rows.Item(0) oRejected = oRow.ItemEx("CUST_REJECTED", False) oHistoryId = oRow.Item("GUID") Catch ex As Exception Logger.Warn("Error while converting REJECTED: " & ex.Message) oRejected = False End Try Dim oOriginalName As Object = GetOriginalFilename(pFile.Name) Logger.Info("File with MessageId [{0}] and Filename [{1}] has already been processed.", pMessageId, oOriginalName) ' If the file was already rejected, it is allowed to be processed again, ' even if the Checksum exists in the history entries (default case) ' Which means, if it was not rejected before, it will be rejected in any case! ' ' This logic can be overwritten by the IgnoreRejectionStatus parameter. ' If it is set to true, the file will be rejected if the file exists in the history entries, ' regardless of the rejected parameter. If oRejected = True And pIgnoreRejectionStatus = True Then Logger.Info("ZuGFeRDFile already has been processed, but Rejection Status will be ignored!") ElseIf oRejected = False Then Logger.Info("ZuGFeRDFile already has been processed. Will be rejected.") Throw New MD5HashException($"There is already an identical invoice! - HistoryID [{oHistoryId}] - Case 1", oOriginalName) Else Logger.Info("ZuGFeRDFile already has been processed. Will be rejected.") Throw New MD5HashException($"There is already an identical invoice! - HistoryID [{oHistoryId}] - Case 2", oOriginalName) End If Return oMD5CheckSum End Function Public Function GetOriginalFilename(pFilename As String) As String ' Try to get the original filename from Attachment table ' If this fails, falls back to the new filename (~Attm.ext) Dim oSQL = $"SELECT EMAIL_ATTMT FROM TBEMLP_HISTORY_ATTACHMENT WHERE EMAIL_ATTMT_INDEX = '{pFilename}'" Dim oEmailAttachment = Database.GetScalarValue(oSQL, MSSQLServer.TransactionMode.NoTransaction) Dim oOriginalName = ObjectEx.NotNull(oEmailAttachment, pFilename) Return oOriginalName End Function Private Function CreateMD5(pFilename As String) As String Try Dim oMD5 As New MD5CryptoServiceProvider Dim oHash As Byte() Dim oHashString As String Dim oResult As String = "" Using oFileStream As New FileStream(pFilename, FileMode.Open, FileAccess.Read, FileShare.Read, 8192) oHash = oMD5.ComputeHash(oFileStream) oHashString = BitConverter.ToString(oHash) End Using oResult = oHashString.Replace("-", "") Return oResult Catch ex As Exception Logger.Error(ex) Return "" End Try End Function End Class