test_mode = get_option('test_mode_enabled'); // Load the model using the full module path $this->ci->load->model('paystack/paystack_model'); $this->setId('paystack'); $this->setName('Paystack'); /** * Enhanced settings with additional security options */ $this->setSettings([ [ 'name' => 'paystack_secret_key', 'encrypted' => true, 'label' => 'Paystack Secret Key', 'type' => 'input' ], [ 'name' => 'paystack_public_key', 'label' => 'Paystack Public Key', 'type' => 'input' ], [ 'name' => 'test_mode_enabled', 'label' => 'Test Mode', 'type' => 'yes_no', 'default_value' => 1 ], [ 'name' => 'currencies', 'label' => 'settings_paymentmethod_currencies', 'default_value' => 'NGN,USD,GHS,ZAR' ], [ 'name' => 'webhook_secret', 'encrypted' => true, 'label' => 'Webhook Secret', 'type' => 'input' ], [ 'name' => 'max_retry_attempts', 'label' => 'Maximum Retry Attempts', 'type' => 'input', 'default_value' => '3' ] ]); } /** * Process the payment with validation and security checks */ public function process_payment($data) { try { // Log the payment data for debugging $this->ci->paystack_model->add_payment_log([ 'invoice_id' => $data['invoiceid'], 'amount' => $data['amount'], 'message' => 'Payment process initiated', 'log_type' => 'debug' ]); // Generate payment reference $reference = 'INV_' . $data['invoiceid'] . '_' . time(); // Store transaction data $transaction_data = [ 'invoice_id' => $data['invoiceid'], 'reference' => $reference, 'email' => $data['client']->email, 'amount' => $data['amount'], 'status' => 'pending', 'transaction_date' => date('Y-m-d H:i:s') ]; $this->ci->db->insert(db_prefix() . 'paystack_transactions', $transaction_data); // Return HTML for the payment form return $this->generate_payment_form($data, $reference); } catch (Exception $e) { // Log any errors $this->ci->paystack_model->add_payment_log([ 'invoice_id' => $data['invoiceid'], 'message' => 'Error: ' . $e->getMessage(), 'log_type' => 'error' ]); return false; } } private function generate_payment_form($data, $reference) { $public_key = $this->getSetting('paystack_public_key'); $form = '
'; return $form; } /** * Record payment with additional validation */ public function record_payment($invoice_id, $transaction) { // Validate transaction data if (!$this->validate_transaction_data($transaction)) { $this->log_error('Invalid transaction data for payment recording'); return false; } $payment_data = [ 'amount' => $transaction['data']->amount / 100, 'invoiceid' => $invoice_id, 'paymentmode' => $this->getId(), 'transactionid' => $transaction['data']->reference, 'note' => 'Paystack Transaction Reference: ' . $transaction['data']->reference ]; // Record payment $this->ci->load->model('payments_model'); $payment_id = $this->ci->payments_model->add($payment_data); if ($payment_id) { $this->update_invoice_status($invoice_id); $this->log_success($transaction['data']->reference, $payment_data['amount']); return true; } $this->log_error('Failed to record payment for invoice #' . $invoice_id); return false; } /** * Make secure API request */ protected function make_api_request($endpoint, $method = 'GET', $data = null) { $url = $this->api_url . $endpoint; $secret_key = $this->get_secret_key(); $headers = [ 'Authorization: Bearer ' . $secret_key, 'Cache-Control: no-cache' ]; if ($data && in_array($method, ['POST', 'PUT'])) { $headers[] = 'Content-Type: application/json'; } $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => true, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_HTTPHEADER => $headers ]); if ($data && in_array($method, ['POST', 'PUT'])) { curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); } $response = curl_exec($ch); $error = curl_error($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $this->log_api_request($endpoint, $method, $data, $http_code, $error); if ($error) { return [ 'success' => false, 'message' => $error ]; } $result = json_decode($response); if (!$result || !$result->status) { return [ 'success' => false, 'message' => isset($result->message) ? $result->message : 'Invalid response' ]; } return [ 'success' => true, 'data' => $result ]; } /** * Validation methods */ protected function validate_payment_data($data) { $required_fields = ['amount', 'invoiceid', 'currency']; foreach ($required_fields as $field) { if (!isset($data[$field]) || empty($data[$field])) { $this->log_error('Missing required field: ' . $field); return false; } } return true; } protected function validate_payment_amount($amount) { return is_numeric($amount) && $amount > 0; } protected function validate_payment_currency($currency) { $allowed_currencies = explode(',', get_option('currencies')); return in_array(strtoupper($currency), $allowed_currencies); } public function verify_transaction($reference) { $secret_key = $this->decryptSetting('paystack_secret_key'); $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => "https://api.paystack.co/transaction/verify/" . rawurlencode($reference), CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . $secret_key, "Cache-Control: no-cache", ], ]); $response = curl_exec($ch); $err = curl_error($ch); curl_close($ch); if ($err) { $this->ci->paystack_model->add_payment_log([ 'message' => 'Verification Error: ' . $err, 'log_type' => 'error' ]); return [ 'success' => false, 'message' => $err ]; } $result = json_decode($response); return [ 'success' => true, 'data' => $result->data ]; } /** * Security methods */ protected function encrypt_payment_data($data) { $this->ci->load->library('encryption'); return $this->ci->encryption->encrypt(serialize($data)); } protected function decrypt_payment_data($encrypted_data) { if (!$encrypted_data) return false; $this->ci->load->library('encryption'); $decrypted = $this->ci->encryption->decrypt($encrypted_data); return $decrypted ? unserialize($decrypted) : false; } protected function get_secret_key() { $key_option = $this->test_mode ? 'paystack_test_secret_key' : 'paystack_live_secret_key'; return $this->decryptSetting($key_option); } /** * Rate limiting */ protected function check_rate_limit($invoice_id) { $max_attempts = get_option('max_retry_attempts'); $timeframe = 15; // minutes $this->ci->load->model('paystack_model'); $attempts = $this->ci->paystack_model->get_recent_failed_attempts($invoice_id, $timeframe); return $attempts < $max_attempts; } /** * Logging methods */ protected function log_payment_attempt($invoice_id, $amount) { $this->ci->load->model('paystack_model'); $this->ci->paystack_model->add_payment_log([ 'invoice_id' => $invoice_id, 'amount' => $amount, 'log_type' => 'attempt', 'message' => 'Payment attempt initiated' ]); } protected function log_api_request($endpoint, $method, $data, $http_code, $error = null) { $this->ci->load->model('paystack_model'); $this->ci->paystack_model->add_payment_log([ 'log_type' => 'api_request', 'message' => json_encode([ 'endpoint' => $endpoint, 'method' => $method, 'http_code' => $http_code, 'error' => $error ]) ]); } protected function log_success($reference, $amount) { $this->ci->load->model('paystack_model'); $this->ci->paystack_model->add_payment_log([ 'log_type' => 'success', 'message' => "Payment successful - Reference: $reference, Amount: $amount" ]); } protected function log_error($message) { $this->ci->load->model('paystack_model'); $this->ci->paystack_model->add_payment_log([ 'log_type' => 'error', 'message' => $message ]); } }