fix: resolve all Week 2 performance & security issues (F1.10–F1.19)

Security:
- Replace maybe_serialize() in cookies with json_encode() (PHP object injection fix)
- Add PayPal webhook signature verification
- Add current_user_can('manage_options') to all 18 admin-ajax handlers

Performance:
- Remove flush_rewrite_rules() from init hooks (Thankyou + Payment)
- Add activation/deactivation hooks for flush_rewrite_rules
- Cache currency, country, flags JSON reads in static variables
- Add server-side pagination to Customer::formipay_tabledata_customers()
- Optimize Order::formipay_tabledata_orders() with COUNT(*) GROUP BY

Cleanup:
- Delete Paypal.phpbak backup file
- Fix timezone hardcode Asia/Jakarta → wp_timezone_string()
- Create uninstall.php for proper cleanup on uninstall

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dwindown
2026-04-17 19:52:01 +07:00
parent be9a1a0a86
commit 66e7b37f92
15 changed files with 341 additions and 868 deletions

View File

@@ -729,10 +729,45 @@ class Paypal extends Payment {
public function handle_paypal_webhook(\WP_REST_Request $request) {
$body = $request->get_body();
$event = json_decode($body, true);
if (!$event || empty($event['event_type'])) {
return new \WP_Error('invalid_webhook', 'Invalid webhook payload');
}
// Verify webhook signature
$formipay_settings = get_option('formipay_settings');
$headers = $request->get_headers();
$auth_algo = $headers['paypal_auth_algo'][0] ?? '';
$transmission_id = $headers['paypal_transmission_id'][0] ?? '';
$cert_url = $headers['paypal_cert_url'][0] ?? '';
$transmission_sig = $headers['paypal_transmission_sig'][0] ?? '';
$transmission_time = $headers['paypal_transmission_time'][0] ?? '';
$webhook_id = $formipay_settings['paypal_webhook_id'] ?? '';
if (!empty($webhook_id) && !empty($transmission_id) && !empty($transmission_sig)) {
$expected = $transmission_id . '|' . $event['resource']['id'] ?? '' . '|' . $transmission_time . '|' . $webhook_id . '|' . crc32($body);
$sig_base64 = base64_encode($expected);
// Fetch certificate and verify
$cert_response = wp_remote_get($cert_url);
if (is_wp_error($cert_response)) {
return new \WP_Error('cert_fetch_failed', 'Failed to fetch PayPal certificate');
}
$cert = wp_remote_retrieve_body($cert_response);
$public_key = openssl_pkey_get_public($cert);
if ($public_key === false) {
return new \WP_Error('invalid_cert', 'Failed to load PayPal certificate');
}
$verified = openssl_verify($expected, base64_decode($transmission_sig), $public_key, 'sha256WithRSAEncryption');
openssl_free_key($public_key);
if ($verified !== 1) {
return new \WP_Error('invalid_signature', 'Webhook signature verification failed');
}
}
// Example: get order_id from custom_id or invoice_number in resource
$resource = $event['resource'];