Skip to content
This repository has been archived by the owner on May 6, 2020. It is now read-only.

Commit

Permalink
Validate documents hash if the saft file was created by SolRIA
Browse files Browse the repository at this point in the history
  • Loading branch information
fredericoregateiro committed Jul 31, 2018
1 parent daa8b2e commit 87d4520
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 43 deletions.
4 changes: 3 additions & 1 deletion src/SolRIA.SaftAnalyser.Logic/Interfaces/ISaftValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ public interface ISaftValidator
int GetSaftErrors();
int GetSaftHeaderErrors();
int GetSaftCustomersErrors();
}
int GetSaftHashValidationNumber();
int GetSaftHashValidationErrorNumber();
}
}
183 changes: 155 additions & 28 deletions src/SolRIA.SaftAnalyser.Logic/OpenedFileInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.Xml.Linq;
using System.Xml.Schema;
using System.Linq;
using System.Globalization;

namespace SolRIA.SaftAnalyser
{
Expand Down Expand Up @@ -41,7 +42,9 @@ public static OpenedFileInstance Instance
System.Globalization.CultureInfo enCulture = new System.Globalization.CultureInfo("en-US");

public string SaftFileName { get; set; }
public string StockFileName { get; set; }
public AuditFile SaftFile { get; set; }
public SolRia.Erp.Models.Stocks.StocksFile.StockFile StockFile { get; set; }

List<Error> mensagensErro;
public List<Error> MensagensErro
Expand All @@ -55,6 +58,9 @@ public List<Error> MensagensErro
set { mensagensErro = value; }
}

public int SaftHashValidationNumber { get; set; }
public int SaftHashValidationErrorNumber { get; set; }

/// <summary>
/// Loads the SAFT file
/// </summary>
Expand Down Expand Up @@ -137,6 +143,12 @@ public async Task OpenSaftFile(string filename)
if (SaftFile.SourceDocuments != null && SaftFile.SourceDocuments.WorkingDocuments != null)
ValidateWorkDocument(SaftFile.SourceDocuments.WorkingDocuments);

//check for solria saft, if true validate the hash
SaftHashValidationNumber = 0;
SaftHashValidationErrorNumber = 0;
if (SaftFile.Header.SoftwareCertificateNumber == "2340")
SolRiaValidateSaftHash(SaftFile);

//remove empty messages
MensagensErro.RemoveAll(c => c == null || string.IsNullOrEmpty(c.Description));
}
Expand All @@ -147,6 +159,149 @@ public async Task OpenSaftFile(string filename)
}
}

public async Task OpenStockFile(string filename)
{
StockFileName = filename;

StockFile = await XmlSerializer.Deserialize<SolRia.Erp.Models.Stocks.StocksFile.StockFile>(StockFileName);
}

private void SolRiaValidateSaftHash(AuditFile auditFile)
{
object hasher = SHA1.Create();

using (RSACryptoServiceProvider rsaCryptokey = new RSACryptoServiceProvider(1024))
{
rsaCryptokey.FromXmlString("<RSAKeyValue><Modulus>vU9AbSDUgXjuKEHl8UaYWfboVz0YRnMMspGHxZ59aJSEYwMYPNsmakNBS9is3+BGXd3AVlthaPmNW5BUuzICNyCQ+DldQ9dP8jr7xcyv1+E5xrMobF8+4xD2ST+DuAUw41ZTCZA3/r47BXonF/DWx+PpVhS68zorDWiJZUJGVg8=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>");

StringBuilder toHash = new StringBuilder();

//invoices
if (auditFile.SourceDocuments.SalesInvoices != null)
{
for (int i = 0; i < auditFile.SourceDocuments.SalesInvoices.Invoice.Length; i++)
{
SourceDocumentsSalesInvoicesInvoice invoice = auditFile.SourceDocuments.SalesInvoices.Invoice[i];

bool usaHashAnterior = true;
if (i == 0 || invoice.InvoiceType != auditFile.SourceDocuments.SalesInvoices.Invoice[i - 1].InvoiceType || Convert.ToInt32(invoice.InvoiceNo.Split('/')[1]) != Convert.ToInt32(auditFile.SourceDocuments.SalesInvoices.Invoice[i - 1].InvoiceNo.Split('/')[1]) + 1)
usaHashAnterior = false;

//ignore the first documents on each billing numbers, there is no way to verify these without the hash of the previous documents
if (usaHashAnterior == false)
continue;

//check for invoice hash
if (SolRiaHashExists(invoice.Hash, invoice.InvoiceNo) == false)
continue;

//build the hash
SolRiaBuildHash(toHash, invoice.InvoiceDate, invoice.SystemEntryDate, invoice.InvoiceNo, invoice.DocumentTotals.GrossTotal, usaHashAnterior ? auditFile.SourceDocuments.SalesInvoices.Invoice[i - 1].Hash : "");

SolRiaIsHashValid(toHash.ToString(), invoice.Hash, rsaCryptokey, hasher, invoice.InvoiceNo);
}
}

//movement of goods
if (auditFile.SourceDocuments.MovementOfGoods != null)
{
for (int i = 0; i < auditFile.SourceDocuments.MovementOfGoods.StockMovement.Length; i++)
{
SourceDocumentsMovementOfGoodsStockMovement movement = auditFile.SourceDocuments.MovementOfGoods.StockMovement[i];

bool usaHashAnterior = true;
if (i == 0 || movement.MovementType != auditFile.SourceDocuments.MovementOfGoods.StockMovement[i - 1].MovementType || Convert.ToInt32(movement.DocumentNumber.Split('/')[1]) != Convert.ToInt32(auditFile.SourceDocuments.MovementOfGoods.StockMovement[i - 1].DocumentNumber.Split('/')[1]) + 1)
usaHashAnterior = false;

//ignore the first documents on each billing numbers, there is no way to verify these without the hash of the previous documents
if (usaHashAnterior == false)
continue;

//check for invoice hash
if (SolRiaHashExists(movement.Hash, movement.DocumentNumber) == false)
continue;

//build the hash
SolRiaBuildHash(toHash, movement.MovementDate, movement.SystemEntryDate, movement.DocumentNumber, movement.DocumentTotals.GrossTotal, usaHashAnterior ? auditFile.SourceDocuments.MovementOfGoods.StockMovement[i - 1].Hash : "");

SolRiaIsHashValid(toHash.ToString(), movement.Hash, rsaCryptokey, hasher, movement.DocumentNumber);
}
}

//working documents
if (auditFile.SourceDocuments.WorkingDocuments != null)
{
for (int i = 0; i < auditFile.SourceDocuments.WorkingDocuments.WorkDocument.Length; i++)
{
SourceDocumentsWorkingDocumentsWorkDocument document = auditFile.SourceDocuments.WorkingDocuments.WorkDocument[i];

bool usaHashAnterior = true;
if (i == 0 || document.WorkType != auditFile.SourceDocuments.WorkingDocuments.WorkDocument[i - 1].WorkType || Convert.ToInt32(document.DocumentNumber.Split('/')[1]) != Convert.ToInt32(auditFile.SourceDocuments.WorkingDocuments.WorkDocument[i - 1].DocumentNumber.Split('/')[1]) + 1)
usaHashAnterior = false;

//ignore the first documents on each billing numbers, there is no way to verify these without the hash of the previous documents
if (usaHashAnterior == false)
continue;

//check for invoice hash
if (SolRiaHashExists(document.Hash, document.DocumentNumber) == false)
continue;

//build the hash
SolRiaBuildHash(toHash, document.WorkDate, document.SystemEntryDate, document.DocumentNumber, document.DocumentTotals.GrossTotal, usaHashAnterior ? auditFile.SourceDocuments.WorkingDocuments.WorkDocument[i - 1].Hash : "");

SolRiaIsHashValid(toHash.ToString(), document.Hash, rsaCryptokey, hasher, document.DocumentNumber);
}
}
}
}

private bool SolRiaHashExists(string hash, string documentNo)
{
if (string.IsNullOrEmpty(hash))
{
MensagensErro.Add(new Error { Description = string.Format("Erro dados: A assinatura do documento {0} não existe.", documentNo) });

return false;
}

return true;
}

private void SolRiaBuildHash(StringBuilder toHash, DateTime documentDate, DateTime systemEntryDate, string documentNo, decimal documentTotal, string hashAnterior)
{
toHash.Clear();

toHash.AppendFormat("{0};{1};{2};{3};{4}"
, documentDate.ToString("yyyy-MM-dd")
, systemEntryDate.ToString("yyyy-MM-ddTHH:mm:ss")
, documentNo
, documentTotal.ToString("0.00", CultureInfo.InvariantCulture)
, hashAnterior);
}

private bool SolRiaIsHashValid(string generatedHash, string fileHash, RSACryptoServiceProvider rsaCryptokey, object hasher, string documentNo)
{
byte[] stringToHashBuffer = Encoding.UTF8.GetBytes(generatedHash);
byte[] hashBuffer = Convert.FromBase64String(fileHash);

//verifi the hash with the public key
bool isHashCorrect = rsaCryptokey.VerifyData(stringToHashBuffer, hasher, hashBuffer);

//add error message if the document hash is incorrect
if (isHashCorrect == false)
{
MensagensErro.Add(new Error { Description = string.Format("Erro dados: A assinatura do documento {0} é inválida.", documentNo) });

SaftHashValidationErrorNumber++;
return false;
}

SaftHashValidationNumber++;
return true;
}


/// <summary>
/// Validate the hashes in the file for the sales invoices
/// </summary>
Expand Down Expand Up @@ -239,34 +394,6 @@ void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
// Mediator.Instance.NotifyColleaguesAsync<Error[]>(MessageType.ERROR_FOUND, MensagensErro.ToArray());
}

void bw_DoWork(object sender, DoWorkEventArgs e)
{
MensagensErro.Clear();

//if (File.Exists(e.Argument.ToString()))
//{
// SaftFile = XmlSerializer.Deserialize<AuditFile>(e.Argument.ToString());
// FileVersion = SaftFileVersion.V10301;

// if (SaftFile == null)
// {
// //try to open the old version
// Model.V2.AuditFile oldSaftFile = XmlSerializer.Deserialize<Model.V2.AuditFile>(e.Argument.ToString());
// //convert the old to the new version
// SaftFile = ConvertV2ToV3.Convert(oldSaftFile);
// FileVersion = SaftFileVersion.V10201;
// }
// if (SaftFile == null)
// {
// //try to open the old version
// Model.V1.AuditFile oldSaftFile = XmlSerializer.Deserialize<Model.V1.AuditFile>(e.Argument.ToString());
// //convert the old to the new version
// SaftFile = ConvertV1ToV3.Convert(oldSaftFile);
// FileVersion = SaftFileVersion.V10101;
// }
//}
}

void bw_RunWorkerCompletedHash(object sender, RunWorkerCompletedEventArgs e)
{
//if (MensagensErro != null && e.Cancelled == false)
Expand Down
17 changes: 12 additions & 5 deletions src/SolRIA.SaftAnalyser.Logic/Services/SaftValidator.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
using SolRia.Erp.MobileApp.Models.SaftV4;
using SolRIA.SaftAnalyser.Interfaces;
using SolRIA.SaftAnalyser.Models;
using System;
using System.Collections.Generic;
using System.Linq;

namespace SolRIA.SaftAnalyser.Services
{
public class SaftValidator : ISaftValidator
public class SaftValidator : ISaftValidator
{
public int GetSaftErrors()
{
Expand All @@ -23,5 +20,15 @@ public int GetSaftCustomersErrors()
{
return OpenedFileInstance.Instance.MensagensErro.Where(c => c.TypeofError == typeof(Customer)).Count();
}
}

public int GetSaftHashValidationNumber()
{
return OpenedFileInstance.Instance.SaftHashValidationNumber;
}

public int GetSaftHashValidationErrorNumber()
{
return OpenedFileInstance.Instance.SaftHashValidationErrorNumber;
}
}
}
30 changes: 27 additions & 3 deletions src/SolRIA.SaftAnalyser/ViewModels/HomeViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using SolRIA.SaftAnalyser.Interfaces;
using SolRIA.SaftAnalyser.Views;
using System;
using System.IO;
using System.Linq;

namespace SolRIA.SaftAnalyser.ViewModels
{
Expand All @@ -23,13 +25,17 @@ public HomeViewModel(IFileService fileService, INavigationService navService, IM

//init commands
OpenSaftFileCommand = new DelegateCommand(OnOpenSaftFile);
}
OpenStockFileCommand = new DelegateCommand(OnOpenStockFile);
}

public DelegateCommand OpenSaftFileCommand { get; private set; }
public async virtual void OnOpenSaftFile()
public async void OnOpenSaftFile()
{
string file = fileService.ChooseFile(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "Ficheiros XMl", "(*.xml)|*.xml");

if (string.IsNullOrWhiteSpace(file) || File.Exists(file) == false)
return;

await OpenedFileInstance.Instance.OpenSaftFile(file);

if (OpenedFileInstance.Instance.SaftFile != null)
Expand All @@ -52,7 +58,25 @@ public async virtual void OnOpenSaftFile()
}
}

private void OpenedEventHandler(object sender, DialogOpenedEventArgs eventargs)
public DelegateCommand OpenStockFileCommand { get; private set; }
public async void OnOpenStockFile()
{
string file = fileService.ChooseFile(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "Ficheiros XMl", "(*.xml)|*.xml");

if (string.IsNullOrWhiteSpace(file) || File.Exists(file) == false)
return;

await OpenedFileInstance.Instance.OpenStockFile(file);

if(OpenedFileInstance.Instance.StockFile != null)
{
var sumProducts = OpenedFileInstance.Instance.StockFile.Stock.Sum(c => c.ClosingStockQuantity);
var totalProducts = OpenedFileInstance.Instance.StockFile.Stock.Length;
var totalDistinctProducts = OpenedFileInstance.Instance.StockFile.Stock.Distinct().Count();
}
}

private void OpenedEventHandler(object sender, DialogOpenedEventArgs eventargs)
{

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ public void Init(Header header)
TotalErrors = saftValidator.GetSaftErrors();
HeaderErrors = saftValidator.GetSaftHeaderErrors();
CustomersErrors = saftValidator.GetSaftCustomersErrors();
}
SaftHashValidationNumber = saftValidator.GetSaftHashValidationNumber();
SaftHashValidationErrorNumber = saftValidator.GetSaftHashValidationErrorNumber();
}

private Header header;
public Header Header
Expand Down Expand Up @@ -55,7 +57,21 @@ public int CustomersErrors
set { SetProperty(ref customersErrors, value); }
}

public DelegateCommand OpenHeaderCommand { get; private set; }
private int saftHashValidationNumber;
public int SaftHashValidationNumber
{
get { return saftHashValidationNumber; }
set { SetProperty(ref saftHashValidationNumber, value); }
}

private int saftHashValidationErrorNumber;
public int SaftHashValidationErrorNumber
{
get { return saftHashValidationErrorNumber; }
set { SetProperty(ref saftHashValidationErrorNumber, value); }
}

public DelegateCommand OpenHeaderCommand { get; private set; }
public virtual void OnOpenHeader()
{
navService.Navigate(PagesIds.SAFT_HEADER);
Expand Down
2 changes: 1 addition & 1 deletion src/SolRIA.SaftAnalyser/Views/Home.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
<Separator Grid.Row="2" Style="{StaticResource MaterialDesignDarkSeparator}" Margin="8 0 8 0"/>

<StackPanel Grid.Row="3">
<Button Style="{StaticResource MaterialDesignFlatButton}" HorizontalAlignment="Left" Margin="8 4 8 8">Escolher ficheiro</Button>
<Button Command="{Binding OpenStockFileCommand}" Style="{StaticResource MaterialDesignFlatButton}" HorizontalAlignment="Left" Margin="8 4 8 8">Escolher ficheiro</Button>
</StackPanel>
</Grid>
</materialDesign:Card>
Expand Down
15 changes: 12 additions & 3 deletions src/SolRIA.SaftAnalyser/Views/SaftValidationResume.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<TextBlock Text="Total erros:" Grid.Column="0" Grid.Row="0"/>
<TextBlock Text="{Binding TotalErrors}" Grid.Column="1" HorizontalAlignment="Right" Grid.Row="0"/>
Expand All @@ -80,7 +82,14 @@
<TextBlock Text="{Binding CustomersErrors}"/>
</Hyperlink>
</TextBlock>
</Grid>

<TextBlock Text="Assinaturas validadas:" Grid.Column="0" Grid.Row="3"/>
<TextBlock HorizontalAlignment="Right" Grid.Column="1" Grid.Row="3" Text="{Binding SaftHashValidationNumber}"/>

<TextBlock Text="Assinaturas com erro:" Grid.Column="0" Grid.Row="4"/>
<TextBlock HorizontalAlignment="Right" Grid.Column="1" Grid.Row="4" Text="{Binding SaftHashValidationErrorNumber}"/>

</Grid>
</GroupBox>

<StackPanel Grid.Row="2" HorizontalAlignment="Right">
Expand Down

0 comments on commit 87d4520

Please sign in to comment.