NestPay Payten 3D-1004 - Guvenlik Kodu hatali. Çözümü
3D-1004 - Guvenlik Kodu hatali. Çözümü - Hash Version 3 - SHA512;
/// <summary>
/// EstNestPay için 3D Secure form data hazırlama (NestPay dokümanına göre)
/// </summary>
public static Dictionary<string, string> Prepare3DFormData(
PaymentRequest request,
BankPOSSettings posSettings,
string callbackBaseUrl,
string bankCode)
{
var amount = request.Amount.ToString("F2", System.Globalization.CultureInfo.InvariantCulture);
var expiryYear = request.ExpiryYear.Length == 4 ? request.ExpiryYear : $"20{request.ExpiryYear}";
var expiryYearShort = expiryYear.Substring(2); // Son 2 rakam
var expiryMonth = request.ExpiryMonth.PadLeft(2, '0'); // 2 haneli ay
var okUrl = $"{callbackBaseUrl}/NestPayCallback3D?bank={bankCode}&status=success&transactionId={request.TransactionId}";
var failUrl = $"{callbackBaseUrl}/NestPayCallback3D?bank={bankCode}&status=failed&transactionId={request.TransactionId}";
// Rastgele dize oluştur (20 karakter)
var rnd = Guid.NewGuid().ToString("N").Substring(0, 20);
// NestPay dokümanına göre parametreler
var formData = new Dictionary<string, string>
{
["clientid"] = posSettings.MerchantId,
["storetype"] = "3D",
["islemtipi"] = "Auth",
["amount"] = amount,
["currency"] = "949", // TRY
["oid"] = request.OrderId,
["okUrl"] = okUrl,
["failUrl"] = failUrl,
["lang"] = "tr", // Türkçe
["rnd"] = rnd,
["pan"] = request.CardNumber,
["Ecom_Payment_Card_ExpDate_Year"] = expiryYearShort,
["Ecom_Payment_Card_ExpDate_Month"] = expiryMonth,
["hashAlgorithm"] = "ver3"
};
// İsteğe bağlı parametreler
if (request.Installments > 1)
formData["taksit"] = request.Installments.ToString();
else
formData["taksit"] = "";
// CVV varsa ekle
if (!string.IsNullOrEmpty(request.CVV))
{
formData["cv2"] = request.CVV;
}
// Hash hesapla (Hash Version 3 - SHA512)
// Hash hesaplamasından önce hash parametresini eklememeliyiz
var hash = CalculateHash3D(formData, posSettings.SecretKey);
formData["hash"] = hash;
return formData;
}
/// <summary>
/// EstNestPay için hash hesaplama (Hash Version 3 - SHA512)
/// NestPay Hash Version 3 dokümanına göre:
/// 1. Tüm parametreler (storeKey hariç) alfabetik olarak sıralanır
/// 2. Parametre değerlerindeki "|" -> "\|", "\" -> "\\" escape edilir
/// 3. Parametreler arasına "|" konulur
/// 4. Sonuna "|" ile storeKey eklenir
/// 5. "encoding" ve "hash" parametreleri hash hesaplamasına dahil edilmez
/// </summary>
public static string CalculateHash3D(Dictionary<string, string> parameters, string storeKey)
{
// "encoding" ve "hash" parametrelerini hash hesaplamasından çıkar
var hashParams = parameters
.Where(p => !string.Equals(p.Key, "encoding", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(p.Key, "hash", StringComparison.OrdinalIgnoreCase))
.OrderBy(p => p.Key, StringComparer.OrdinalIgnoreCase)
.ToList();
// Hash string'i oluştur
var hashParts = new List<string>();
foreach (var param in hashParams)
{
// Parametre değerindeki özel karakterleri escape et
var escapedValue = EscapeHashValue(param.Value ?? "");
hashParts.Add(escapedValue);
}
// Sonuna storeKey ekle
var hashString = string.Join("|", hashParts) + "|" + storeKey;
// SHA-512 ile hash hesapla ve Base64 encode et
using var sha512 = SHA512.Create();
var hashBytes = sha512.ComputeHash(Encoding.ASCII.GetBytes(hashString));
return Convert.ToBase64String(hashBytes);
}
/// <summary>
/// Hash hesaplaması için parametre değerlerindeki özel karakterleri escape eder
/// "|" -> "\|", "\" -> "\\"
/// </summary>
private static string EscapeHashValue(string value)
{
if (string.IsNullOrEmpty(value))
return value;
// Önce "\" karakterlerini "\\" olarak escape et
value = value.Replace("\\", "\\\\");
// Sonra "|" karakterlerini "\|" olarak escape et
value = value.Replace("|", "\\|");
return value;
}