"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); } ?>