158 lines
5.2 KiB
PHP
158 lines
5.2 KiB
PHP
<?php
|
|
// File: detail_tagihan.php
|
|
|
|
// Aktifkan error log
|
|
error_reporting(E_ALL);
|
|
ini_set('display_errors', 0);
|
|
|
|
// === Konfigurasi lokasi log ===
|
|
$log_file = __DIR__ . '/flow_request.log';
|
|
|
|
// === Fungsi logging ===
|
|
function write_log($data, $file) {
|
|
$log_entry = "[" . date('Y-m-d H:i:s') . "] " . $data . PHP_EOL;
|
|
file_put_contents($file, $log_entry, FILE_APPEND);
|
|
}
|
|
|
|
// === Header default ===
|
|
header('Content-Type: application/json');
|
|
|
|
// === Verifikasi kode publik dari Meta ===
|
|
if (isset($_GET['public_code'])) {
|
|
$public_code = $_GET['public_code'];
|
|
// Kirim balik kode publik agar Meta bisa memverifikasi endpoint
|
|
$response = [
|
|
"status" => "ok",
|
|
"public_code" => $public_code
|
|
];
|
|
write_log("Public Code Verification: " . json_encode($response), $log_file);
|
|
echo json_encode($response);
|
|
exit;
|
|
}
|
|
|
|
// === Baca input JSON dari Meta ===
|
|
$raw_input = file_get_contents("php://input");
|
|
write_log("Raw Request: " . $raw_input, $log_file);
|
|
|
|
try {
|
|
$body = json_decode($raw_input, true);
|
|
if (!$body) {
|
|
throw new Exception('Invalid JSON input');
|
|
}
|
|
|
|
// Ambil private key dari environment
|
|
$privatePem = getenv('PRIVATE_KEY');
|
|
if (!$privatePem) {
|
|
throw new Exception('Private key not found in environment');
|
|
}
|
|
|
|
// Dekripsi request
|
|
$decryptedData = decryptRequest($body, $privatePem);
|
|
|
|
// Simulasi ambil data pelanggan (bisa dari DB nantinya)
|
|
$requestData = $decryptedData['decryptedBody'];
|
|
$id_pelanggan = $requestData['id_pelanggan'] ?? 'PLG001';
|
|
$flow_token = $requestData['flow_token'] ?? 'UNKNOWN_TOKEN';
|
|
|
|
// Misal data dari database
|
|
$data_tagihan = [
|
|
"id_pelanggan" => $id_pelanggan,
|
|
"nama_pelanggan" => "Wian Darussalam",
|
|
"paket_layanan" => "Internet 20 Mbps",
|
|
"harga_layanan" => 200000,
|
|
"jumlah_potongan" => 0,
|
|
"jumlah_tagihan" => 200000,
|
|
"jumlah_ppn" => 20000,
|
|
"jumlah_diskon" => 0,
|
|
"total_tagihan" => 220000,
|
|
"tanggal_limit" => "2025-10-30"
|
|
];
|
|
|
|
// === Format respon sesuai panduan Meta untuk DETAIL_TAGIHAN ===
|
|
$screen = [
|
|
"screen" => "DETAIL_TAGIHAN",
|
|
"data" => [
|
|
"extension_message_response" => [
|
|
"params" => [
|
|
"flow_token" => $flow_token,
|
|
"id_pelanggan" => $data_tagihan['id_pelanggan'],
|
|
"nama_pelanggan" => $data_tagihan['nama_pelanggan'],
|
|
"paket_layanan" => $data_tagihan['paket_layanan'],
|
|
"harga_layanan" => $data_tagihan['harga_layanan'],
|
|
"jumlah_potongan" => $data_tagihan['jumlah_potongan'],
|
|
"jumlah_tagihan" => $data_tagihan['jumlah_tagihan'],
|
|
"jumlah_ppn" => $data_tagihan['jumlah_ppn'],
|
|
"jumlah_diskon" => $data_tagihan['jumlah_diskon'],
|
|
"total_tagihan" => $data_tagihan['total_tagihan'],
|
|
"tanggal_limit" => $data_tagihan['tanggal_limit']
|
|
]
|
|
]
|
|
]
|
|
];
|
|
|
|
// Enkripsi response
|
|
$resBody = encryptResponse($screen, $decryptedData['aesKeyBuffer'], $decryptedData['initialVectorBuffer']);
|
|
|
|
// Tulis log response
|
|
write_log("Response: " . json_encode($screen), $log_file);
|
|
|
|
// === Kirim respon ke Meta ===
|
|
echo $resBody;
|
|
|
|
} catch (Exception $e) {
|
|
$error = ["error" => $e->getMessage()];
|
|
write_log("Error: " . json_encode($error), $log_file);
|
|
|
|
http_response_code(500);
|
|
echo json_encode($error);
|
|
}
|
|
|
|
function decryptRequest($body, $privatePem)
|
|
{
|
|
$encryptedAesKey = base64_decode($body['encrypted_aes_key']);
|
|
$encryptedFlowData = base64_decode($body['encrypted_flow_data']);
|
|
$initialVector = base64_decode($body['initial_vector']);
|
|
|
|
// Load private key
|
|
$privateKey = openssl_pkey_get_private($privatePem);
|
|
if (!$privateKey) {
|
|
throw new Exception('Failed to load private key');
|
|
}
|
|
|
|
// Decrypt the AES key
|
|
$decryptedAesKey = '';
|
|
if (!openssl_private_decrypt($encryptedAesKey, $decryptedAesKey, $privateKey, OPENSSL_PKCS1_OAEP_PADDING)) {
|
|
throw new Exception('Decryption of AES key failed');
|
|
}
|
|
|
|
// Decrypt the Flow data using AES-GCM
|
|
$tagLength = 16;
|
|
$encryptedFlowDataBody = substr($encryptedFlowData, 0, -$tagLength);
|
|
$tag = substr($encryptedFlowData, -$tagLength);
|
|
|
|
$decrypted = openssl_decrypt($encryptedFlowDataBody, 'aes-128-gcm', $decryptedAesKey, OPENSSL_RAW_DATA, $initialVector, $tag);
|
|
if ($decrypted === false) {
|
|
throw new Exception('Decryption of flow data failed');
|
|
}
|
|
|
|
return [
|
|
'decryptedBody' => json_decode($decrypted, true),
|
|
'aesKeyBuffer' => $decryptedAesKey,
|
|
'initialVectorBuffer' => $initialVector,
|
|
];
|
|
}
|
|
|
|
function encryptResponse($response, $aesKeyBuffer, $initialVectorBuffer)
|
|
{
|
|
// Flip the initialization vector
|
|
$flipped_iv = ~$initialVectorBuffer;
|
|
|
|
// Encrypt the response data using AES-GCM
|
|
$cipher = openssl_encrypt(json_encode($response), 'aes-128-gcm', $aesKeyBuffer, OPENSSL_RAW_DATA, $flipped_iv, $tag);
|
|
if ($cipher === false) {
|
|
throw new Exception('Encryption of response failed');
|
|
}
|
|
|
|
return base64_encode($cipher . $tag);
|
|
}
|
|
?>
|