-
Notifications
You must be signed in to change notification settings - Fork 329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Stripe Payment #679
base: main
Are you sure you want to change the base?
[WIP] Stripe Payment #679
Changes from all commits
634b095
182cdd6
3b33496
d5cee46
019153e
84df0f8
808c4da
46b2a2f
62c2ed4
040cec2
728231d
c76fe9e
f40ae36
f14f932
d421bf7
9c825b8
7f8a7cd
f67e487
452ab15
d0fd417
5936d60
641b5b7
ccf0d7c
0213224
b18b4e8
f7c8f02
2936343
c851879
208629b
088cf45
00a3acc
d341b54
c5ed0c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,118 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<?php | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
namespace App\Http\Controllers\Forms; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
use App\Http\Controllers\Controller; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
use App\Models\OAuthProvider; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
use Illuminate\Http\Request; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
use Illuminate\Support\Facades\Log; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
use Stripe\Stripe; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
use Stripe\PaymentIntent; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
class FormPaymentController extends Controller | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public function getAccount(Request $request) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$form = $request->form; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Get payment block (only one allowed) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$paymentBlock = collect($form->properties)->first(fn ($prop) => $prop['type'] === 'payment'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!$paymentBlock) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Log::warning('Form without payment block', [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'form_id' => $form->id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return $this->error(['message' => 'Form does not have a payment block.']); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Get provider | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$provider = OAuthProvider::find($paymentBlock['stripe_account_id']); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ($provider === null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Log::error('Failed to find Stripe account', [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'stripe_account_id' => $paymentBlock['stripe_account_id'] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return $this->error(['message' => 'Failed to find Stripe account']); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return $this->success(['stripeAccount' => $provider->provider_user_id]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public function createIntent(Request $request) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$form = $request->form; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Verify form exists and is accessible | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ($form->workspace === null || $form->visibility !== 'public') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Log::warning('Attempt to create payment for invalid form', [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'form_id' => $form->id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return $this->error(['message' => 'Form not found.'], 404); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Get payment block (only one allowed) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$paymentBlock = collect($form->properties)->first(fn ($prop) => $prop['type'] === 'payment'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!$paymentBlock) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Log::warning('Attempt to create payment for form without payment block', [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'form_id' => $form->id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return $this->error(['message' => 'Form does not have a payment block.']); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Get provider | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$provider = OAuthProvider::find($paymentBlock['stripe_account_id']); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ($provider === null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Log::error('Failed to find Stripe account', [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'stripe_account_id' => $paymentBlock['stripe_account_id'] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return $this->error(['message' => 'Failed to find Stripe account']); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Log::info('Creating payment intent', [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'form_id' => $form->id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'amount' => $paymentBlock['amount'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'currency' => $paymentBlock['currency'] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stripe::setApiKey(config('cashier.secret')); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$intent = PaymentIntent::create([ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'description' => 'Form - ' . $form->title, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'amount' => (int) ($paymentBlock['amount'] * 100), // Stripe requires amount in cents | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'currency' => strtolower($paymentBlock['currency']), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'payment_method_types' => ['card'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'metadata' => [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'form_id' => $form->id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'workspace_id' => $form->workspace_id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'form_name' => $form->title, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
], [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'stripe_account' => $provider->provider_user_id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Log::info('Payment intent created', [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'form_id' => $form->id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'intent' => $intent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ($intent->id) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return $this->success([ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'intent' => ['id' => $intent->id, 'secret' => $intent->client_secret] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return $this->error(['message' => 'Failed to create payment intent']); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (\Stripe\Exception\CardException $e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Log::warning('Failed to create payment intent', [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'form_id' => $form->id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'message' => $e->getMessage() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return $this->error(['message' => $e->getMessage()]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (\Exception $e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Log::error('Failed to create payment intent', [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'form_id' => $form->id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'error' => $e->getMessage() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return $this->error(['message' => 'Failed to initialize payment.']); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+104
to
+116
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve error handling granularity. The catch blocks could be more specific to handle different Stripe exceptions differently. - } catch (\Stripe\Exception\CardException $e) {
+ } catch (\Stripe\Exception\CardException $e) {
Log::warning('Failed to create payment intent', [
'form_id' => $form->id,
'message' => $e->getMessage()
]);
return $this->error(['message' => $e->getMessage()]);
+ } catch (\Stripe\Exception\InvalidRequestException $e) {
+ Log::error('Invalid Stripe request', [
+ 'form_id' => $form->id,
+ 'error' => $e->getMessage()
+ ]);
+ return $this->error(['message' => 'Invalid payment configuration.']);
+ } catch (\Stripe\Exception\AuthenticationException $e) {
+ Log::critical('Stripe authentication failed', [
+ 'form_id' => $form->id,
+ 'error' => $e->getMessage()
+ ]);
+ return $this->error(['message' => 'Payment service configuration error.']);
} catch (\Exception $e) { 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -49,6 +49,7 @@ public function toArray($request) | |||||||||||||||||||||||||||
'max_number_of_submissions_reached' => $this->max_number_of_submissions_reached, | ||||||||||||||||||||||||||||
'form_pending_submission_key' => $this->form_pending_submission_key, | ||||||||||||||||||||||||||||
'max_file_size' => $this->max_file_size / 1000000, | ||||||||||||||||||||||||||||
'auto_save' => $this->getAutoSave(), | ||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
|
@@ -112,4 +113,16 @@ private function getCleanigns() | |||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||
return $this->extra?->cleanings ?? $this->cleanings; | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
private function hasPaymentBlock() | ||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||
return array_filter($this->properties, function ($property) { | ||||||||||||||||||||||||||||
return $property['type'] === 'payment'; | ||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
Comment on lines
+117
to
+122
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve the hasPaymentBlock() method implementation. The current implementation has several issues:
Consider this improved implementation: private function hasPaymentBlock()
{
- return array_filter($this->properties, function ($property) {
- return $property['type'] === 'payment';
- });
+ if (!isset($this->properties)) {
+ return false;
+ }
+ return (bool) array_search('payment', array_column($this->properties, 'type'));
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
private function getAutoSave() | ||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||
return $this->hasPaymentBlock() ? true : $this->auto_save; | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
Comment on lines
+124
to
+127
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Fix hasPaymentBlock to return boolean instead of array The current implementation of Please update the implementation: private function hasPaymentBlock()
{
- return array_filter($this->properties, function ($property) {
+ return collect($this->properties)->contains(function ($property) {
return $property['type'] === 'payment';
});
} 🔗 Analysis chainDocument the auto-save requirement for payment forms. The implementation enforces auto-save for forms with payment blocks, but this important business rule isn't documented. Additionally, the current implementation might not work as intended due to Please:
/**
+ * Get the auto_save value for the form.
+ * Forms with payment blocks must have auto_save enabled to ensure payment data persistence.
+ *
+ * @return bool
+ */
private function getAutoSave()
{
- return $this->hasPaymentBlock() ? true : $this->auto_save;
+ return $this->hasPaymentBlock() || $this->auto_save;
} 🏁 Scripts executedThe following scripts were executed for the analysis: Error: No shell scripts found Script: #!/bin/bash
# Find hasPaymentBlock implementation
echo "=== hasPaymentBlock implementation ==="
ast-grep --pattern 'function hasPaymentBlock() {
$$$
}'
echo -e "\n=== FormResource test files ==="
fd -e php test FormResource
echo -e "\n=== Other usages of hasPaymentBlock ==="
rg "hasPaymentBlock" -A 2
Length of output: 1910 Script: #!/bin/bash
# Get complete implementation of hasPaymentBlock method
echo "=== Complete hasPaymentBlock implementation ==="
rg -U "private function hasPaymentBlock\(\).*?\}" --multiline api/app/Http/Resources/FormResource.php
Length of output: 208 Script: #!/bin/bash
echo "=== FormResource.php content ==="
cat api/app/Http/Resources/FormResource.php
Length of output: 4245 |
||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,78 @@ | ||||||||||||||||||||||||||||||||||||||||||||
<?php | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
namespace App\Integrations\OAuth\Drivers; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
use App\Integrations\OAuth\Drivers\Contracts\OAuthDriver; | ||||||||||||||||||||||||||||||||||||||||||||
use Laravel\Socialite\Contracts\User; | ||||||||||||||||||||||||||||||||||||||||||||
use Laravel\Socialite\Facades\Socialite; | ||||||||||||||||||||||||||||||||||||||||||||
use Illuminate\Support\Facades\Auth; | ||||||||||||||||||||||||||||||||||||||||||||
use Illuminate\Support\Facades\Log; | ||||||||||||||||||||||||||||||||||||||||||||
use SocialiteProviders\Stripe\Provider as StripeProvider; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
class OAuthStripeDriver implements OAuthDriver | ||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||
private ?string $redirectUrl = null; | ||||||||||||||||||||||||||||||||||||||||||||
private ?array $scopes = []; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
protected StripeProvider $provider; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
public function __construct() | ||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||
$this->provider = Socialite::driver('stripe'); | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
public function getRedirectUrl(): string | ||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||
$user = Auth::user(); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
$params = [ | ||||||||||||||||||||||||||||||||||||||||||||
'stripe_user[email]' => $user->email, | ||||||||||||||||||||||||||||||||||||||||||||
'stripe_user[url]' => config('app.url'), | ||||||||||||||||||||||||||||||||||||||||||||
'stripe_user[business_name]' => $user->name, | ||||||||||||||||||||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
Log::info('Initiating Stripe Connect flow', [ | ||||||||||||||||||||||||||||||||||||||||||||
'user_id' => $user->id | ||||||||||||||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+34
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Avoid logging sensitive user information. The log message includes user ID which could be considered PII. Consider using a hash or removing it if not essential for debugging. - Log::info('Initiating Stripe Connect flow', [
- 'user_id' => $user->id
- ]);
+ Log::info('Initiating Stripe Connect flow'); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
return $this->provider | ||||||||||||||||||||||||||||||||||||||||||||
->scopes($this->scopes ?? []) | ||||||||||||||||||||||||||||||||||||||||||||
->stateless() | ||||||||||||||||||||||||||||||||||||||||||||
->redirectUrl($this->redirectUrl ?? config('services.stripe.redirect')) | ||||||||||||||||||||||||||||||||||||||||||||
->with($params) | ||||||||||||||||||||||||||||||||||||||||||||
->redirect() | ||||||||||||||||||||||||||||||||||||||||||||
->getTargetUrl(); | ||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+38
to
+44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for Stripe API calls. The redirect URL generation doesn't handle potential exceptions from the Stripe API. This could result in unhandled exceptions reaching the user. + try {
return $this->provider
->scopes($this->scopes ?? [])
->stateless()
->redirectUrl($this->redirectUrl ?? config('services.stripe.redirect'))
->with($params)
->redirect()
->getTargetUrl();
+ } catch (\Exception $e) {
+ Log::error('Failed to generate Stripe redirect URL', [
+ 'error' => $e->getMessage()
+ ]);
+ throw new \RuntimeException('Failed to connect to Stripe. Please try again later.');
+ } 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
public function getUser(): User | ||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||
return $this->provider | ||||||||||||||||||||||||||||||||||||||||||||
->stateless() | ||||||||||||||||||||||||||||||||||||||||||||
->redirectUrl($this->redirectUrl ?? config('services.stripe.redirect')) | ||||||||||||||||||||||||||||||||||||||||||||
->user(); | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
public function canCreateUser(): bool | ||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||
return true; | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
public function setRedirectUrl(string $url): OAuthDriver | ||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||
$this->redirectUrl = $url; | ||||||||||||||||||||||||||||||||||||||||||||
return $this; | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+60
to
+64
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validate redirect URL to prevent open redirect vulnerability. The setRedirectUrl method accepts any URL without validation, which could lead to open redirect vulnerabilities. + private function isValidRedirectUrl(string $url): bool
+ {
+ $allowedDomains = [parse_url(config('app.url'), PHP_URL_HOST)];
+ $urlHost = parse_url($url, PHP_URL_HOST);
+ return in_array($urlHost, $allowedDomains);
+ }
public function setRedirectUrl(string $url): OAuthDriver
{
+ if (!$this->isValidRedirectUrl($url)) {
+ throw new \InvalidArgumentException('Invalid redirect URL');
+ }
$this->redirectUrl = $url;
return $this;
}
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
public function setScopes(array $scopes): OAuthDriver | ||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||
$this->scopes = $scopes; | ||||||||||||||||||||||||||||||||||||||||||||
return $this; | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
public function fullScopes(): OAuthDriver | ||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||
return $this->setScopes([ | ||||||||||||||||||||||||||||||||||||||||||||
'read_write', | ||||||||||||||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
use Illuminate\Support\Facades\Storage; | ||
use Illuminate\Support\Facades\URL; | ||
use Illuminate\Support\Facades\Validator; | ||
use Illuminate\Support\Facades\Event; | ||
use Illuminate\Support\ServiceProvider; | ||
use Laravel\Cashier\Cashier; | ||
use Laravel\Dusk\DuskServiceProvider; | ||
|
@@ -40,6 +41,10 @@ public function boot() | |
} | ||
|
||
Validator::includeUnvalidatedArrayKeys(); | ||
|
||
Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) { | ||
$event->extendSocialite('stripe', \SocialiteProviders\Stripe\Provider::class); | ||
}); | ||
Comment on lines
+44
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Missing Stripe OAuth Environment Variables Documentation The Stripe OAuth configuration is properly structured in Please add these required variables to
🔗 Analysis chainLGTM! Verify Stripe OAuth configuration. The Stripe OAuth provider is correctly integrated using Laravel Socialite's event listener pattern. Run this script to verify the OAuth configuration: 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Verify Stripe OAuth configuration
# Test: Check if required OAuth config exists in services.php
echo "Checking services.php for Stripe OAuth configuration..."
rg "stripe.*=>.*\[" config/services.php -A 5
# Test: Check if required environment variables are documented
echo "Checking .env.example for Stripe OAuth variables..."
rg "STRIPE.*(CLIENT_ID|CLIENT_SECRET|REDIRECT)" .env.example
Length of output: 456 Script: #!/bin/bash
# Search for config files and env examples
echo "Searching for config files..."
fd -t f "services" -E "node_modules"
echo -e "\nSearching for env files..."
fd -t f ".env" -E "node_modules"
echo -e "\nSearching for Stripe-related configuration in any file..."
rg -l "STRIPE" -t php -t env
Length of output: 475 Script: #!/bin/bash
echo "Checking services.php content..."
cat api/config/services.php
echo -e "\nChecking environment files for Stripe configuration..."
echo "=== client/.env.example ==="
cat client/.env.example
echo -e "\n=== client/.env.docker ==="
cat client/.env.docker
echo -e "\n=== scripts/setup-env.sh ==="
cat scripts/setup-env.sh
Length of output: 7910 |
||
} | ||
|
||
/** | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use round or int to handle fractional amounts.
Casting using
(int)
floors the amount. If a user enters$10.99
, it will become1099
which is correct, but$10.999
becomes1099
instead of1100
. Decide whether to round or floor intentionally.📝 Committable suggestion