223 lines
6.8 KiB
Go
223 lines
6.8 KiB
Go
package http
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt" // NEW
|
|
"github.com/tuusuario/go-sync-service/internal/http/external_api"
|
|
"log"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/tuusuario/go-sync-service/internal/config"
|
|
"github.com/tuusuario/go-sync-service/internal/domain/dto"
|
|
"github.com/tuusuario/go-sync-service/internal/domain/model"
|
|
"github.com/tuusuario/go-sync-service/internal/domain/ports"
|
|
)
|
|
|
|
var (
|
|
redisKey = "session:SAP"
|
|
mutex sync.Mutex
|
|
)
|
|
|
|
type SAPSessionProvider struct{}
|
|
|
|
func GetSession(cfg ports.RedisConfigProvider, job dto.CronJob, auth dto.ServiceConfig, dbcore ports.Database, logPrefix string) (*dto.SessionData, error) {
|
|
//CLIENT HTTP
|
|
authenticacion, _, err := Authenticacion(job.UnidadNegocio.CompanyDB)
|
|
if err != nil {
|
|
log.Printf("Error en autenticacion: %v", err)
|
|
return nil, err
|
|
}
|
|
|
|
return &dto.SessionData{
|
|
Headers: authenticacion.Data.Headers,
|
|
ExpiresAt: authenticacion.Data.ExpiresAt,
|
|
EndPoint: authenticacion.Data.URL,
|
|
}, nil
|
|
|
|
/*
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
redisKey = "session:" + job.UnidadNegocio.CompanyName + ":" + job.UnidadNegocio.CompanyDB
|
|
//REDIS
|
|
if sess, err := loadSessionFromRedis(cfg, logPrefix); err == nil && time.Now().Before(sess.ExpiresAt) {
|
|
config.Log.Printf("%v 🔑 Sesión obtenida de Redis %v", logPrefix, redisKey)
|
|
return sess, nil
|
|
}
|
|
|
|
|
|
|
|
|
|
parametros := map[string]interface{}{
|
|
"company_name": job.UnidadNegocio.CompanyName,
|
|
"company_db": job.UnidadNegocio.CompanyDB,
|
|
}
|
|
|
|
credencial, err := dbcore.GetCredencialesFromTemplate(config.GlobalConfig.WhereUnitsBusiness, parametros)
|
|
if err != nil {
|
|
config.Log.Printf("%v ❌ Error al obtener credenciales: %v", logPrefix, err)
|
|
return nil, err
|
|
}
|
|
|
|
// ==============================
|
|
// DESCIFRAR PASSWORD (AES-GCM)
|
|
// ==============================
|
|
key, err := security.LoadEncryptionKey()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%s %v", logPrefix, err)
|
|
}
|
|
// Suponemos que credencial.Password viene como base64(nonce||cipher) generado por EncryptAESGCM
|
|
plainPass, err := security.DecryptAESGCM(credencial.Password, key)
|
|
if err != nil {
|
|
config.Log.Printf("%v ❌ Error al descifrar password: %v", logPrefix, err)
|
|
return nil, err
|
|
}
|
|
credencial.Password = plainPass
|
|
|
|
// No loguees secretos. Si necesitas log, hazlo sin password:
|
|
config.Log.Debugf("%v Obteniendo credenciales para CompanyDB=%s UserName=%s (password oculto)",
|
|
logPrefix, credencial.CompanyDB, credencial.UserName)
|
|
|
|
config.Log.Printf("%v 🔑 Realizando login...", logPrefix)
|
|
|
|
mySession := &dto.SessionData{EndPoint: credencial.EndPoint}
|
|
|
|
if auth.Rest == nil {
|
|
auth.Rest = &dto.RestOptions{}
|
|
}
|
|
|
|
// 3. Preparar el body del login (usa cred.Password en claro ya descifrado)
|
|
auth = prepareAuthBody(auth, credencial, logPrefix)
|
|
|
|
config.Log.Debugf(" %v Url: %v + %v", logPrefix, credencial.EndPoint, auth.Path)
|
|
resp, err := SendRequest(credencial.EndPoint, auth)
|
|
if err != nil || resp.IsError() {
|
|
config.Log.Printf("%v ❌ Error al autenticar: %v", logPrefix, err)
|
|
return nil, err
|
|
}
|
|
|
|
if auth.GQL {
|
|
var dataGraphql struct {
|
|
Token string `json:"token"`
|
|
RefreshToken string `json:"refresh_token"`
|
|
}
|
|
if err := json.Unmarshal(resp.Body(), &dataGraphql); err != nil {
|
|
config.Log.Printf("%v ❌ Error al parsear sesión graphql: %v", logPrefix, err)
|
|
return nil, err
|
|
}
|
|
mySession.SessionId = dataGraphql.Token
|
|
mySession.ExpiresAt = time.Now().Add(10 * time.Minute)
|
|
} else {
|
|
var dataRest struct {
|
|
SessionId string `json:"SessionId"`
|
|
SessionTimeout int `json:"SessionTimeout"`
|
|
}
|
|
if err := json.Unmarshal(resp.Body(), &dataRest); err != nil {
|
|
config.Log.Printf("%v ❌ Error al parsear sesión rest: %v", logPrefix, err)
|
|
return nil, err
|
|
}
|
|
mySession.SessionId = dataRest.SessionId
|
|
mySession.ExpiresAt = time.Now().Add(time.Duration(dataRest.SessionTimeout) * time.Minute)
|
|
}
|
|
|
|
config.Log.Printf("%v ✅ Sesión obtenida", logPrefix)
|
|
saveSessionToRedis(mySession, cfg, logPrefix)
|
|
return mySession, nil
|
|
*/
|
|
}
|
|
|
|
func loadSessionFromRedis(cfg ports.RedisConfigProvider, logPrefix string) (*dto.SessionData, error) {
|
|
raw, err := cfg.GetString(redisKey)
|
|
if err != nil {
|
|
config.Log.Printf("%v ⚠️ No se pudo obtener sesión de Redis: %v", logPrefix, err)
|
|
return nil, err
|
|
}
|
|
var sess dto.SessionData
|
|
if err := json.Unmarshal([]byte(raw), &sess); err != nil {
|
|
config.Log.Printf("%v ⚠️ No se pudo parsear sesión de Redis: %v", logPrefix, err.Error())
|
|
return nil, err
|
|
}
|
|
return &sess, nil
|
|
}
|
|
|
|
func saveSessionToRedis(sess *dto.SessionData, cfg ports.RedisConfigProvider, logPrefix string) {
|
|
data, _ := json.Marshal(sess)
|
|
ttl := time.Until(sess.ExpiresAt)
|
|
err := cfg.UpdateParam(redisKey, string(data), ttl)
|
|
if err != nil {
|
|
config.Log.Printf("%v ⚠️ No se pudo guardar sesión en Redis: %v", logPrefix, err)
|
|
}
|
|
}
|
|
|
|
func prepareAuthBody(auth dto.ServiceConfig, cred *model.CredencialesSAP, logPrefix string) dto.ServiceConfig {
|
|
if auth.Rest == nil {
|
|
auth.Rest = &dto.RestOptions{}
|
|
}
|
|
|
|
if auth.GQL {
|
|
config.Log.Debugf("%v 🧠 Preparando auth para GraphQL", logPrefix)
|
|
auth.Rest.Body = map[string]string{
|
|
"username": cred.UserName,
|
|
"password": cred.Password,
|
|
}
|
|
} else {
|
|
config.Log.Debugf("%v🧠 Preparando auth para REST", logPrefix)
|
|
auth.Rest.Body = map[string]string{
|
|
"CompanyDB": cred.CompanyDB,
|
|
"UserName": cred.UserName,
|
|
"Password": cred.Password,
|
|
}
|
|
}
|
|
return auth
|
|
}
|
|
|
|
func Authenticacion(company string) (*dto.Response, *dto.RequestTrace, error) {
|
|
url := config.GlobalConfig.AUTH_ENDPOINT
|
|
|
|
headers := map[string]string{
|
|
"Content-Type": "application/json",
|
|
"Authorization": config.GlobalConfig.AUTH_AUTORIZATION,
|
|
}
|
|
|
|
// Crea el cuerpo de la solicitud con el id recibido
|
|
body := []byte(fmt.Sprintf(`{"name": "%s"}`, company))
|
|
|
|
client := external_api.NewGenericClient(3, 3*time.Second)
|
|
// Hacer la solicitud usando el cliente genérico
|
|
response, trace, err := client.DoRequest(config.GlobalConfig.AUTH_METHOD, url, headers, body)
|
|
|
|
// Manejo de errores
|
|
if err != nil {
|
|
log.Println("Error en la solicitud: ", err)
|
|
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Deserializar la respuesta en el modelo de dto.Response
|
|
var responseModel dto.Response
|
|
err = mapToModel(response, &responseModel)
|
|
if err != nil {
|
|
log.Println("Error al deserializar la respuesta: ", err)
|
|
return nil, nil, err
|
|
}
|
|
log.Printf("TRACE: %+v", trace)
|
|
log.Printf("RESPUESTA MAP: %+v", response)
|
|
return &responseModel, trace, nil
|
|
}
|
|
|
|
// mapToModel convierte un mapa genérico en el modelo ResponseModel
|
|
func mapToModel(data map[string]interface{}, model *dto.Response) error {
|
|
// Utiliza json.Marshal y json.Unmarshal para convertir el mapa en el modelo
|
|
jsonData, err := json.Marshal(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = json.Unmarshal(jsonData, model)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|