Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 18 additions & 24 deletions app/Http/Controllers/Auth/GoogleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,29 @@
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Auth; // Added the Auth facade here
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;

class GoogleController extends Controller
{
/**
* Redirect the user to Google specifically for Logging In.
*/
public function login()
{
session(['google_auth_intent' => 'login']);
return Socialite::driver('google')->redirect();
}

/**
* Redirect the user to Google specifically for Registering.
*/
public function register()
{
session(['google_auth_intent' => 'register']);
return Socialite::driver('google')->redirect();
}

/**
* Handle the secure callback from Google.
*/
public function callback(Request $request)
{
try {
$googleUser = Socialite::driver('google')->user();
} catch (\Exception $e) {
return redirect('/dashboard/login')->withErrors([
return redirect()->route('login')->withErrors([
'email' => 'Google authentication was cancelled or failed. Please try again.',
]);
}
Expand All @@ -49,27 +40,29 @@ public function callback(Request $request)
->orWhere('email', $googleUser->getEmail())
->first();

// SCENARIO 1: USER IS TRYING TO LOG IN
if ($intent === 'login') {
if (!$existingUser) {
return redirect('/dashboard/register')->withErrors([
'email' => 'No account found with this Google account. Please register first.',
if ($intent === 'register') {
if ($existingUser) {
return redirect()->route('login')->withErrors([
'email' => 'An account with this email already exists. Please log in instead.',
]);
}

$existingUser->update([
$newUser = User::create([
'name' => $googleUser->getName(),
'email' => $googleUser->getEmail(),
'google_id' => $googleUser->getId(),
'avatar' => $googleUser->getAvatar(),
'password' => Hash::make(Str::random(32)),
]);

Auth::login($existingUser, true); // Fixed red line here
return redirect('/dashboard');
Auth::login($newUser, true);

return redirect()->route('dashboard');
}

// SCENARIO 2: USER IS TRYING TO REGISTER
if ($intent === 'register') {
if ($existingUser) {
return redirect('/dashboard/login')->withErrors([
return redirect()->route('login')->withErrors([
'email' => 'An account with this email already exists. Please log in instead.',
]);
}
Expand All @@ -83,10 +76,11 @@ public function callback(Request $request)
'api_token' => Str::random(60),
]);

Auth::login($newUser, true); // Fixed red line here
return redirect('/dashboard');
Auth::login($newUser, true);

return redirect()->route('dashboard');
}

return redirect('/dashboard/login');
return redirect()->route('login');
}
}
25 changes: 5 additions & 20 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,29 @@
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
use HasFactory, Notifiable;
use HasApiTokens, HasFactory, Notifiable;

/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'email',
'password',
'google_id', // Required for Google OAuth
'avatar', // Required for Google OAuth
'api_token', // Allowed based on migration
'google_id',
'avatar',
];

/**
* The attributes that should be hidden for serialization.
*
* @var list<string>
*/
protected $hidden = [
'password',
'remember_token',
'api_token', // Good practice: Hide API tokens from array/JSON serialization
];

/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
Expand Down
37 changes: 37 additions & 0 deletions app/Support/Csp/CustomPolicy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace App\Support\Csp;

use Spatie\Csp\Directive;
use Spatie\Csp\Keyword;
use Spatie\Csp\Policy;
use Spatie\Csp\Preset;

class CustomPolicy implements Preset
{
public function configure(Policy $policy): void
{
$policy
->add(Directive::IMG, [
Keyword::SELF,
'res.cloudinary.com',
'*.googleusercontent.com',
'data:',
])
->add(Directive::STYLE, [
Keyword::SELF,
Keyword::UNSAFE_INLINE,
'fonts.googleapis.com',
])
->add(Directive::FONT, [
Keyword::SELF,
'fonts.gstatic.com',
'data:',
])
->add(Directive::SCRIPT, [
Keyword::SELF,
Keyword::UNSAFE_INLINE,
Keyword::UNSAFE_EVAL,
]);
}
}
2 changes: 1 addition & 1 deletion bootstrap/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
// This line is CRITICAL for Render to allow file uploads
$middleware->trustProxies(at: '*');
$middleware->append(\Spatie\Csp\AddCspHeaders::class);
})
->withExceptions(function (Exceptions $exceptions) {
//
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"livewire/livewire": "^4.2",
"resend/resend-laravel": "^1.3",
"smalot/pdfparser": "^2.12",
"spatie/laravel-csp": "^3.23",
"spatie/laravel-sitemap": "^8.1"
},
"require-dev": {
Expand Down
87 changes: 86 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 64 additions & 0 deletions config/csp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

return [

/*
* Presets will determine which CSP headers will be set. A valid CSP preset is
* any class that implements `Spatie\Csp\Preset`
*/
'presets' => [
Spatie\Csp\Presets\Basic::class,
App\Support\Csp\CustomPolicy::class,
],

/**
* Register additional global CSP directives here.
*/
'directives' => [
// [Directive::SCRIPT, [Keyword::UNSAFE_EVAL, Keyword::UNSAFE_INLINE]],
],

/*
* These presets which will be put in a report-only policy. This is great for testing out
* a new policy or changes to existing CSP policy without breaking anything.
*/
'report_only_presets' => [
//
],

/**
* Register additional global report-only CSP directives here.
*/
'report_only_directives' => [
// [Directive::SCRIPT, [Keyword::UNSAFE_EVAL, Keyword::UNSAFE_INLINE]],
],

/*
* All violations against a policy will be reported to this url.
* A great service you could use for this is https://report-uri.com/
*/
'report_uri' => env('CSP_REPORT_URI', ''),

/*
* Headers will only be added if this setting is set to true.
*/
'enabled' => env('CSP_ENABLED', true),

/**
* Headers will be added when Vite is hot reloading.
*/
'enabled_while_hot_reloading' => env('CSP_ENABLED_WHILE_HOT_RELOADING', false),

/*
* The class responsible for generating the nonces used in inline tags and headers.
*/
'nonce_generator' => Spatie\Csp\Nonce\RandomString::class,

/*
* Set false to disable automatic nonce generation and handling.
* This is useful when you want to use 'unsafe-inline' for scripts/styles
* and cannot add inline nonces.
* Note that this will make your CSP policy less secure.
*/
'nonce_enabled' => env('CSP_NONCE_ENABLED', true),
];
4 changes: 2 additions & 2 deletions config/session.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@
|
*/

'secure' => env('SESSION_SECURE_COOKIE'),
'secure' => env('SESSION_SECURE_COOKIE', env('APP_ENV') !== 'local'),

/*
|--------------------------------------------------------------------------
Expand Down Expand Up @@ -230,4 +230,4 @@

'serialization' => 'json',

];
];
Loading
Loading