mirror of
https://git.imnavajas.es/jjimenez/erp-imprimelibros.git
synced 2026-01-13 08:58:48 +00:00
falta actualizar bien el resumen
This commit is contained in:
@ -3,8 +3,7 @@ package com.imprimelibros.erp.redsys;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import sis.redsys.api.Signature;
|
||||
import sis.redsys.api.Utils;
|
||||
import sis.redsys.api.ApiMacSha256;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@ -12,7 +11,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@ -20,48 +18,54 @@ import java.util.Objects;
|
||||
public class RedsysService {
|
||||
|
||||
// ---------- CONFIG ----------
|
||||
@Value("${redsys.merchant-code}") private String merchantCode;
|
||||
@Value("${redsys.terminal}") private String terminal;
|
||||
@Value("${redsys.currency}") private String currency;
|
||||
@Value("${redsys.transaction-type}") private String txType;
|
||||
@Value("${redsys.secret-key}") private String secretKeyBase64;
|
||||
@Value("${redsys.urls.ok}") private String urlOk;
|
||||
@Value("${redsys.urls.ko}") private String urlKo;
|
||||
@Value("${redsys.urls.notify}") private String urlNotify;
|
||||
@Value("${redsys.environment}") private String env;
|
||||
@Value("${redsys.merchant-code}")
|
||||
private String merchantCode;
|
||||
@Value("${redsys.terminal}")
|
||||
private String terminal;
|
||||
@Value("${redsys.currency}")
|
||||
private String currency;
|
||||
@Value("${redsys.transaction-type}")
|
||||
private String txType;
|
||||
@Value("${redsys.secret-key}")
|
||||
private String secretKeyBase64;
|
||||
@Value("${redsys.urls.ok}")
|
||||
private String urlOk;
|
||||
@Value("${redsys.urls.ko}")
|
||||
private String urlKo;
|
||||
@Value("${redsys.urls.notify}")
|
||||
private String urlNotify;
|
||||
@Value("${redsys.environment}")
|
||||
private String env;
|
||||
|
||||
// ---------- RECORDS ----------
|
||||
public record PaymentRequest(String order, long amountCents, String description) {}
|
||||
public record FormPayload(String action, String signatureVersion, String merchantParameters, String signature) {}
|
||||
public record PaymentRequest(String order, long amountCents, String description) {
|
||||
}
|
||||
|
||||
public record FormPayload(String action, String signatureVersion, String merchantParameters, String signature) {
|
||||
}
|
||||
|
||||
// ---------- MÉTODO PRINCIPAL ----------
|
||||
public FormPayload buildRedirectForm(PaymentRequest req) throws Exception {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("DS_MERCHANT_AMOUNT", String.valueOf(req.amountCents()));
|
||||
params.put("DS_MERCHANT_ORDER", req.order());
|
||||
params.put("DS_MERCHANT_MERCHANTCODE", merchantCode);
|
||||
params.put("DS_MERCHANT_CURRENCY", currency);
|
||||
params.put("DS_MERCHANT_TRANSACTIONTYPE", txType);
|
||||
params.put("DS_MERCHANT_TERMINAL", terminal);
|
||||
params.put("DS_MERCHANT_MERCHANTNAME", "ImprimeLibros");
|
||||
params.put("DS_MERCHANT_PRODUCTDESCRIPTION", req.description());
|
||||
params.put("DS_MERCHANT_URLOK", urlOk);
|
||||
params.put("DS_MERCHANT_URLKO", urlKo);
|
||||
params.put("DS_MERCHANT_MERCHANTURL", urlNotify);
|
||||
ApiMacSha256 api = new ApiMacSha256();
|
||||
|
||||
// JSON -> Base64
|
||||
String json = new ObjectMapper().writeValueAsString(params);
|
||||
String merchantParametersB64 = Base64.getEncoder()
|
||||
.encodeToString(json.getBytes(StandardCharsets.UTF_8));
|
||||
api.setParameter("DS_MERCHANT_AMOUNT", String.valueOf(req.amountCents()));
|
||||
api.setParameter("DS_MERCHANT_ORDER", req.order()); // Usa 12 dígitos con ceros si puedes
|
||||
api.setParameter("DS_MERCHANT_MERCHANTCODE", merchantCode);
|
||||
api.setParameter("DS_MERCHANT_CURRENCY", currency);
|
||||
api.setParameter("DS_MERCHANT_TRANSACTIONTYPE", txType);
|
||||
api.setParameter("DS_MERCHANT_TERMINAL", terminal);
|
||||
api.setParameter("DS_MERCHANT_MERCHANTURL", urlNotify);
|
||||
api.setParameter("DS_MERCHANT_URLOK", urlOk);
|
||||
api.setParameter("DS_MERCHANT_URLKO", urlKo);
|
||||
|
||||
// Firma SHA-512 (tu JAR)
|
||||
String signature = Signature.createMerchantSignature(secretKeyBase64, req.order(), merchantParametersB64);
|
||||
String merchantParameters = api.createMerchantParameters();
|
||||
String signature = api.createMerchantSignature(secretKeyBase64);
|
||||
|
||||
String action = "test".equalsIgnoreCase(env)
|
||||
? "https://sis-t.redsys.es:25443/sis/realizarPago"
|
||||
: "https://sis.redsys.es/sis/realizarPago";
|
||||
|
||||
return new FormPayload(action, "HMAC_SHA512_V1", merchantParametersB64, signature);
|
||||
return new FormPayload(action, "HMAC_SHA256_V1", merchantParameters, signature);
|
||||
}
|
||||
|
||||
// ---------- STEP 3: Decodificar Ds_MerchantParameters ----------
|
||||
@ -69,40 +73,42 @@ public class RedsysService {
|
||||
|
||||
public Map<String, Object> decodeMerchantParametersToMap(String dsMerchantParametersB64) throws Exception {
|
||||
try {
|
||||
String json = Utils.decodeB64UrlSafeString(
|
||||
dsMerchantParametersB64.getBytes(StandardCharsets.UTF_8)
|
||||
);
|
||||
return MAPPER.readValue(json, new TypeReference<Map<String, Object>>() {});
|
||||
} catch (Exception ignore) {
|
||||
byte[] decoded = Base64.getDecoder().decode(dsMerchantParametersB64);
|
||||
String json = new String(decoded, StandardCharsets.UTF_8);
|
||||
return MAPPER.readValue(json, new TypeReference<Map<String, Object>>() {});
|
||||
return MAPPER.readValue(json, new TypeReference<>() {
|
||||
});
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("No se pudo decodificar Ds_MerchantParameters", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- STEP 4: Validar notificación ----------
|
||||
public RedsysNotification validateAndParseNotification(String dsSignature, String dsMerchantParametersB64) throws Exception {
|
||||
Map<String, Object> mp = decodeMerchantParametersToMap(dsMerchantParametersB64);
|
||||
RedsysNotification notif = new RedsysNotification(mp);
|
||||
public RedsysNotification validateAndParseNotification(String dsSignature, String dsMerchantParametersB64)
|
||||
throws Exception {
|
||||
Map<String, Object> mp = decodeMerchantParametersToMap(dsMerchantParametersB64);
|
||||
RedsysNotification notif = new RedsysNotification(mp);
|
||||
|
||||
if (notif.order == null || notif.order.isBlank()) {
|
||||
throw new IllegalArgumentException("Falta Ds_Order en Ds_MerchantParameters");
|
||||
}
|
||||
|
||||
String expected = Signature.createMerchantSignature(
|
||||
secretKeyBase64, notif.order, dsMerchantParametersB64
|
||||
);
|
||||
|
||||
if (!safeEqualsB64(dsSignature, expected)) {
|
||||
throw new SecurityException("Firma Redsys no válida");
|
||||
}
|
||||
|
||||
return notif;
|
||||
if (notif.order == null || notif.order.isBlank()) {
|
||||
throw new IllegalArgumentException("Falta Ds_Order en Ds_MerchantParameters");
|
||||
}
|
||||
|
||||
ApiMacSha256 api = new ApiMacSha256();
|
||||
api.setParameter("Ds_MerchantParameters", dsMerchantParametersB64);
|
||||
|
||||
String expected = api.createMerchantSignatureNotif(secretKeyBase64, api.decodeMerchantParameters(dsMerchantParametersB64)); // ✅ SOLO UN PARÁMETRO
|
||||
|
||||
if (!safeEqualsB64(dsSignature, expected)) {
|
||||
throw new SecurityException("Firma Redsys no válida");
|
||||
}
|
||||
|
||||
return notif;
|
||||
}
|
||||
|
||||
|
||||
// ---------- HELPERS ----------
|
||||
private static boolean safeEqualsB64(String a, String b) {
|
||||
if (Objects.equals(a, b)) return true;
|
||||
if (Objects.equals(a, b))
|
||||
return true;
|
||||
try {
|
||||
String na = normalizeB64(a);
|
||||
String nb = normalizeB64(b);
|
||||
@ -115,12 +121,16 @@ public class RedsysService {
|
||||
}
|
||||
|
||||
private static String normalizeB64(String s) {
|
||||
if (s == null) return "";
|
||||
if (s == null)
|
||||
return "";
|
||||
String n = s.replace('-', '+').replace('_', '/');
|
||||
int mod = n.length() % 4;
|
||||
if (mod == 2) n += "==";
|
||||
else if (mod == 3) n += "=";
|
||||
else if (mod == 1) n += "===";
|
||||
if (mod == 2)
|
||||
n += "==";
|
||||
else if (mod == 3)
|
||||
n += "=";
|
||||
else if (mod == 1)
|
||||
n += "===";
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -144,12 +154,21 @@ public class RedsysService {
|
||||
try {
|
||||
int r = Integer.parseInt(response);
|
||||
return r >= 0 && r <= 99;
|
||||
} catch (Exception e) { return false; }
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static String str(Object o) {
|
||||
return o == null ? null : String.valueOf(o);
|
||||
}
|
||||
|
||||
private static String str(Object o) { return o == null ? null : String.valueOf(o); }
|
||||
private static long parseLongSafe(Object o) {
|
||||
try { return Long.parseLong(String.valueOf(o)); } catch (Exception e) { return 0L; }
|
||||
try {
|
||||
return Long.parseLong(String.valueOf(o));
|
||||
} catch (Exception e) {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user