diff --git a/examples/endpoint/test-initialize.php b/examples/endpoint/test-initialize.php new file mode 100644 index 00000000..3ac3ae5c --- /dev/null +++ b/examples/endpoint/test-initialize.php @@ -0,0 +1,47 @@ +setAmount('1000') + ->setCurrency(\Flutterwave\Util\Currency::NGN) + ->setCountry('NG') + ->setEmail('test@example.com') + ->setFirstname('John') + ->setLastname('Doe') + ->setPhoneNumber('+2349067985861') + ->setRedirectUrl("http://{$_SERVER['HTTP_HOST']}/examples/endpoint/verify.php") + ->setTitle('Test Payment') # ->setTitle('') change title to this for testing XSS fix + ->setDescription('Testing initialize XSS fix') + ->setLogo('https://mysite.com/logo.png') + ->setPaymentOptions('card,banktransfer'); + + if (!empty($_REQUEST) && isset($_REQUEST['make'])) { + $flw->initialize(); // this renders the full modal page + exit; + } + +} catch (Exception $e) { + $error = $e->getMessage(); +} +?> + + +
+ + + \ No newline at end of file diff --git a/src/Flutterwave.php b/src/Flutterwave.php index b62ce7fc..65a2a401 100644 --- a/src/Flutterwave.php +++ b/src/Flutterwave.php @@ -321,60 +321,38 @@ public function requeryTransaction(string $referenceNumber): object } /** - * Generates the final json to be used in configuring the payment call to the rave payment gateway + * @deprecated Use render('inline')->getHtml() instead. + * Will be removed in a future version. */ public function initialize(): void { + @trigger_error( + 'initialize() is deprecated and will be removed in a future version. Use render(\'inline\')->with([...])->getHtml() instead.', + E_USER_DEPRECATED + ); + $this->createCheckSum(); - $appId = $this->signoz->getAppId(); - $environment = $this->signoz->getCurrentEnvironment(); + $checkoutConfig = [ + 'public_key' => self::$config->getPublicKey(), + 'tx_ref' => $this->txref, + 'amount' => (float) $this->amount, + 'currency' => $this->currency, + 'country' => $this->country, + 'redirect_url' => $this->redirectUrl, + 'payment_method' => $this->paymentOptions, + 'email' => $this->customerEmail, + 'phone_number' => $this->customerPhone, + 'first_name' => $this->customerFirstname, + 'last_name' => $this->customerLastname, + 'customizations' => [ + 'title' => $this->customTitle, + 'description' => $this->customDescription, + 'logo' => $this->customLogo, + ], + ]; - $this->signoz->trackRequestSent($appId, $environment, 'GET', $this->txref, '/inline'); - - $this->logger->info('Rendering Payment Modal..'); - - echo ''; - echo ''; - // $loader_img_src = FLW_PHP_ASSET_DIR."js/v3.js"; - echo '

';
$html .= '';
$html .= '';
$html .= '';
diff --git a/tests/Unit/Checkout/InitializeTest.php b/tests/Unit/Checkout/InitializeTest.php
new file mode 100644
index 00000000..ac3e0159
--- /dev/null
+++ b/tests/Unit/Checkout/InitializeTest.php
@@ -0,0 +1,120 @@
+eventHandler(new ModalEventHandler())
+ ->setAmount('1000')
+ ->setCurrency(\Flutterwave\Util\Currency::NGN)
+ ->setCountry('NG')
+ ->setEmail('test@example.com')
+ ->setFirstname('John')
+ ->setLastname('Doe')
+ ->setPhoneNumber('+2349067985861')
+ ->setRedirectUrl('https://example.com/callback')
+ ->setTitle('Test Payment')
+ ->setDescription('Testing initialize XSS fix')
+ ->setLogo('https://mysite.com/logo.png')
+ ->setPaymentOptions('card,banktransfer');
+
+ return $instance;
+ }
+
+ public function testInitializeEscapesScriptTagInTitle(): void
+ {
+ $instance = $this->buildInstance();
+ $instance->setTitle('');
+
+ ob_start();
+ $instance->initialize();
+ $output = ob_get_clean();
+
+ $this->assertStringNotContainsString('', $output);
+ $this->assertStringContainsString('\u003C', $output);
+ }
+
+ public function testInitializeEscapesQuotesInCustomerName(): void
+ {
+ $instance = $this->buildInstance();
+ $instance->setFirstname("O'Brien");
+ $instance->setLastname('"Hacker"');
+
+ ob_start();
+ $instance->initialize();
+ $output = ob_get_clean();
+
+ $this->assertStringNotContainsString('"Hacker"', $output);
+ $this->assertStringNotContainsString("'Brien", $output);
+ }
+
+ public function testInitializeEscapesRedirectUrl(): void
+ {
+ $instance = $this->buildInstance();
+ $instance->setRedirectUrl('https://evil.com","public_key":"leaked');
+
+ ob_start();
+ $instance->initialize();
+ $output = ob_get_clean();
+
+ $this->assertStringNotContainsString('"public_key":"leaked', $output);
+ }
+
+ public function testInitializeCastsAmountToFloat(): void
+ {
+ $instance = $this->buildInstance();
+ $instance->setAmount('100');
+
+ ob_start();
+ $instance->initialize();
+ $output = ob_get_clean();
+
+ $this->assertStringContainsString('"amount":100.0', $output);
+ }
+
+ public function testInitializeUsesSetPaymentOptions(): void
+ {
+ $instance = $this->buildInstance();
+ $instance->setPaymentOptions('card,banktransfer');
+
+ ob_start();
+ $instance->initialize();
+ $output = ob_get_clean();
+
+ $this->assertStringContainsString('card,banktransfer', $output);
+ }
+
+ public function testInitializeIsDeprecated(): void
+ {
+ $instance = $this->buildInstance();
+
+ $deprecationTriggered = false;
+ set_error_handler(function (int $errno, string $errstr) use (&$deprecationTriggered) {
+ if ($errno === E_USER_DEPRECATED && str_contains($errstr, 'initialize() is deprecated')) {
+ $deprecationTriggered = true;
+ }
+ return true;
+ });
+
+ ob_start();
+ $instance->initialize();
+ ob_get_clean();
+
+ restore_error_handler();
+
+ $this->assertTrue($deprecationTriggered, 'Expected a deprecation notice for initialize()');
+ }
+}
\ No newline at end of file