ProyectoGrupal/VerifactuMidAPI/internal/hash.go

131 lines
2.8 KiB
Go
Raw Permalink Normal View History

package internal
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"time"
)
type HashService struct {
lastRecord *LastRecord
}
type LastRecord struct {
EmisorNIF string
NumSerie string
Fecha time.Time
Huella string
FechaGen time.Time
}
func NewHashService() *HashService {
return &HashService{}
}
func (s *HashService) SetLastRecord(r *LastRecord) {
s.lastRecord = r
}
func (s *HashService) GetLastRecord() *LastRecord {
return s.lastRecord
}
func (s *HashService) CalculateHash(data *InvoiceData, previousHash string) string {
fechaGen := data.FechaGen.Format("2006-01-02T15:04:05-07:00")
fields := fmt.Sprintf(
"IDEmisorFactura=%s&NumSerieFactura=%s&FechaExpedicionFactura=%s&TipoFactura=%s&CuotaTotal=%.2f&ImporteTotal=%.2f&Huella=%s&FechaHoraHusoGenRegistro=%s",
data.EmisorNIF,
data.NumSerie,
data.Fecha.Format("02-01-2006"),
data.TipoFactura,
data.CuotaTotal,
data.ImporteTotal,
previousHash,
fechaGen,
)
hash := sha256.Sum256([]byte(fields))
return strings.ToUpper(hex.EncodeToString(hash[:]))
}
func (s *HashService) IsFirstRecord() bool {
return s.lastRecord == nil
}
func (s *HashService) GetPreviousHash() string {
if s.lastRecord == nil {
return ""
}
return s.lastRecord.Huella
}
type LastRecordStorage interface {
GetLastRecord(emisorNIF string) (*LastRecord, error)
SaveLastRecord(r *LastRecord) error
}
type FileLastRecordStorage struct {
basePath string
}
func NewFileLastRecordStorage(basePath string) *FileLastRecordStorage {
return &FileLastRecordStorage{basePath: basePath}
}
func (s *FileLastRecordStorage) GetLastRecord(emisorNIF string) (*LastRecord, error) {
if s.basePath == "" {
s.basePath = "./data/"
}
filePath := filepath.Join(s.basePath, sanitizeFilename(emisorNIF)+".json")
data, err := os.ReadFile(filePath)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, fmt.Errorf("reading last record: %w", err)
}
var record LastRecord
if err := json.Unmarshal(data, &record); err != nil {
return nil, fmt.Errorf("unmarshaling last record: %w", err)
}
return &record, nil
}
func (s *FileLastRecordStorage) SaveLastRecord(r *LastRecord) error {
if s.basePath == "" {
s.basePath = "./data/"
}
if err := os.MkdirAll(s.basePath, 0750); err != nil {
return fmt.Errorf("creating directory: %w", err)
}
filePath := filepath.Join(s.basePath, sanitizeFilename(r.EmisorNIF)+".json")
data, err := json.Marshal(r)
if err != nil {
return fmt.Errorf("marshaling last record: %w", err)
}
if err := os.WriteFile(filePath, data, 0640); err != nil {
return fmt.Errorf("writing last record: %w", err)
}
return nil
}
func sanitizeFilename(name string) string {
re := regexp.MustCompile(`[^a-zA-Z0-9]`)
return re.ReplaceAllString(name, "_")
}