VerifactuMidAPI/api/handler.go

230 lines
6.0 KiB
Go
Raw Permalink Normal View History

package api
import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"VerifactuMidAPI/internal"
"VerifactuMidAPI/internal/cert"
"VerifactuMidAPI/internal/config"
"VerifactuMidAPI/internal/crypto"
"VerifactuMidAPI/internal/formats"
)
type RegisterInput struct {
CertName string `json:"cert_name"`
CertFile string `json:"cert_file"`
PasswordEncrypted string `json:"password_encrypted"`
}
type Handler struct {
cfg *config.Config
cert *cert.Storage
crypto *crypto.KeyPair
facturaSvc *internal.FacturaService
}
func New(cfg *config.Config, certStorage *cert.Storage, keyPair *crypto.KeyPair, facturaSvc *internal.FacturaService) *Handler {
return &Handler{
cfg: cfg,
cert: certStorage,
crypto: keyPair,
facturaSvc: facturaSvc,
}
}
func (h *Handler) GetPublicKey(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
pubPEM, err := h.crypto.PublicKeyPEM()
if err != nil {
http.Error(w, "failed to get public key", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(fmt.Sprintf(`{"public_key":"%s"}`, base64.StdEncoding.EncodeToString(pubPEM))))
}
func (h *Handler) RegisterCert(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "failed to read body", http.StatusBadRequest)
return
}
var input RegisterInput
if err := json.Unmarshal(body, &input); err != nil {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"success":false,"error":"invalid_json"}`))
return
}
if input.CertName == "" || input.CertFile == "" || input.PasswordEncrypted == "" {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"success":false,"error":"missing_fields"}`))
return
}
decodedPass, err := base64.StdEncoding.DecodeString(input.PasswordEncrypted)
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"success":false,"error":"invalid_password_encrypted"}`))
return
}
plainPassBytes, err := h.crypto.Decrypt(decodedPass)
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"success":false,"error":"decrypt_failed"}`))
return
}
plainPass := string(plainPassBytes)
validation := cert.ValidateP12(input.CertFile, plainPass)
if !validation.Valid {
resp, _ := json.Marshal(map[string]interface{}{
"success": false,
"error": validation.Error,
"cert": validation.CertInfo,
})
w.Header().Set("Content-Type", "application/json")
w.Write(resp)
return
}
tempPath, err := h.cert.StoreFromBase64(input.CertName, input.CertFile)
if err != nil {
h.cert.DeleteTemp(tempPath)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"success":false,"error":"temp_storage_failed"}`))
return
}
if len(validation.Warnings) > 0 {
storedPath, err := h.cert.MoveToPerm(input.CertName, tempPath, plainPass)
if err != nil {
h.cert.DeleteTemp(tempPath)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"success":false,"error":"storage_failed"}`))
return
}
tokenData, err := h.cert.GenerateToken(input.CertName, storedPath, plainPass)
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"success":false,"error":"token_generation_failed"}`))
return
}
resp, _ := json.Marshal(map[string]interface{}{
"success": true,
"cert": validation.CertInfo,
"token": tokenData.Token,
"warnings": validation.Warnings,
})
w.Header().Set("Content-Type", "application/json")
w.Write(resp)
return
}
storedPath, err := h.cert.MoveToPerm(input.CertName, tempPath, plainPass)
if err != nil {
h.cert.DeleteTemp(tempPath)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"success":false,"error":"storage_failed"}`))
return
}
tokenData, err := h.cert.GenerateToken(input.CertName, storedPath, plainPass)
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"success":false,"error":"token_generation_failed"}`))
return
}
resp, _ := json.Marshal(map[string]interface{}{
"success": true,
"cert": validation.CertInfo,
"token": tokenData.Token,
})
w.Header().Set("Content-Type", "application/json")
w.Write(resp)
}
func (h *Handler) HandleFacturas(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "failed to read body", http.StatusBadRequest)
return
}
log.Printf("facturas request: %s", string(body))
output, _ := h.facturaSvc.ProcessAlta(body)
log.Printf("facturas output:%+v", output)
resp, _ := json.Marshal(output)
w.Header().Set("Content-Type", "application/json")
w.Write(resp)
}
func (h *Handler) HandleFacturasAnular(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "failed to read body", http.StatusBadRequest)
return
}
var input internal.AnulacionInput
if err := json.Unmarshal(body, &input); err != nil {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"success":false,"error":"invalid_json"}`))
return
}
output, _ := h.facturaSvc.ProcessAnulacion(input)
resp, _ := json.Marshal(output)
w.Header().Set("Content-Type", "application/json")
w.Write(resp)
}
func (h *Handler) ListFormats(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
available := formats.Available()
resp, _ := json.Marshal(map[string]interface{}{
"formats": available,
})
w.Header().Set("Content-Type", "application/json")
w.Write(resp)
}