diff --git a/app/Http/Middleware/App/HandleInertiaRequests.php b/app/Http/Middleware/App/HandleInertiaRequests.php index dab26efc..6deda69c 100644 --- a/app/Http/Middleware/App/HandleInertiaRequests.php +++ b/app/Http/Middleware/App/HandleInertiaRequests.php @@ -47,6 +47,7 @@ public function share(Request $request): array 'name' => $name, ])->values()->all(), 'selfHosted' => config('trypost.self_hosted'), + 'googleAuthEnabled' => config('trypost.google_auth_enabled'), ]; } } diff --git a/config/trypost.php b/config/trypost.php index 20dd458e..32ce9b60 100644 --- a/config/trypost.php +++ b/config/trypost.php @@ -16,6 +16,18 @@ 'self_hosted' => env('SELF_HOSTED', true), + /* + |-------------------------------------------------------------------------- + | Google Authentication + |-------------------------------------------------------------------------- + | + | Enable or disable "Login with Google" on the login and register pages. + | Disable this if you don't have Google OAuth credentials configured. + | + */ + + 'google_auth_enabled' => env('GOOGLE_AUTH_ENABLED', false), + /* |-------------------------------------------------------------------------- | Social Platforms @@ -29,40 +41,40 @@ 'platforms' => [ 'linkedin' => [ - 'enabled' => env('TRYPOST_LINKEDIN_ENABLED', true), + 'enabled' => env('LINKEDIN_ENABLED', true), ], 'linkedin-page' => [ - 'enabled' => env('TRYPOST_LINKEDIN_PAGE_ENABLED', true), + 'enabled' => env('LINKEDIN_PAGE_ENABLED', true), ], 'x' => [ - 'enabled' => env('TRYPOST_X_ENABLED', true), + 'enabled' => env('X_ENABLED', true), ], 'tiktok' => [ - 'enabled' => env('TRYPOST_TIKTOK_ENABLED', true), + 'enabled' => env('TIKTOK_ENABLED', true), ], 'youtube' => [ - 'enabled' => env('TRYPOST_YOUTUBE_ENABLED', true), + 'enabled' => env('YOUTUBE_ENABLED', true), ], 'facebook' => [ - 'enabled' => env('TRYPOST_FACEBOOK_ENABLED', true), + 'enabled' => env('FACEBOOK_ENABLED', true), ], 'instagram' => [ - 'enabled' => env('TRYPOST_INSTAGRAM_ENABLED', true), + 'enabled' => env('INSTAGRAM_ENABLED', true), ], 'instagram-facebook' => [ - 'enabled' => env('TRYPOST_INSTAGRAM_FACEBOOK_ENABLED', true), + 'enabled' => env('INSTAGRAM_FACEBOOK_ENABLED', true), ], 'threads' => [ - 'enabled' => env('TRYPOST_THREADS_ENABLED', true), + 'enabled' => env('THREADS_ENABLED', true), ], 'pinterest' => [ - 'enabled' => env('TRYPOST_PINTEREST_ENABLED', true), + 'enabled' => env('PINTEREST_ENABLED', true), ], 'bluesky' => [ - 'enabled' => env('TRYPOST_BLUESKY_ENABLED', true), + 'enabled' => env('BLUESKY_ENABLED', true), ], 'mastodon' => [ - 'enabled' => env('TRYPOST_MASTODON_ENABLED', true), + 'enabled' => env('MASTODON_ENABLED', true), ], ], diff --git a/resources/js/pages/auth/Login.vue b/resources/js/pages/auth/Login.vue index 9d5a1b9f..2be5550e 100644 --- a/resources/js/pages/auth/Login.vue +++ b/resources/js/pages/auth/Login.vue @@ -66,16 +66,18 @@ defineProps<{ -
- {{ $t('auth.or_continue_with') }} -
+
{{ $t('auth.login.no_account') }} diff --git a/resources/js/pages/auth/Register.vue b/resources/js/pages/auth/Register.vue index 4f59fc62..0fa1becd 100644 --- a/resources/js/pages/auth/Register.vue +++ b/resources/js/pages/auth/Register.vue @@ -123,16 +123,18 @@ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
-
- {{ $t('auth.or_continue_with') }} -
+
{{ $t('auth.register.has_account') }} diff --git a/tests/Feature/GoogleAuthToggleTest.php b/tests/Feature/GoogleAuthToggleTest.php new file mode 100644 index 00000000..bb01975e --- /dev/null +++ b/tests/Feature/GoogleAuthToggleTest.php @@ -0,0 +1,71 @@ + false]); + + $response = $this->get(route('login')); + + $response->assertOk(); +}); + +test('login page loads when google auth is enabled', function () { + config(['trypost.google_auth_enabled' => true]); + + $response = $this->get(route('login')); + + $response->assertOk(); +}); + +test('register page loads when google auth is disabled', function () { + config(['trypost.google_auth_enabled' => false]); + + $response = $this->get(route('register')); + + $response->assertOk(); +}); + +test('register page loads when google auth is enabled', function () { + config(['trypost.google_auth_enabled' => true]); + + $response = $this->get(route('register')); + + $response->assertOk(); +}); + +test('login page shares google auth enabled prop as false when disabled', function () { + config(['trypost.google_auth_enabled' => false]); + + $response = $this->get(route('login')); + + $response->assertOk(); + + $page = $response->original->getData()['page']; + expect($page['props']['googleAuthEnabled'])->toBeFalse(); +}); + +test('login page shares google auth enabled prop as true when enabled', function () { + config(['trypost.google_auth_enabled' => true]); + + $response = $this->get(route('login')); + + $response->assertOk(); + + $page = $response->original->getData()['page']; + expect($page['props']['googleAuthEnabled'])->toBeTrue(); +}); + +test('google auth redirect route exists', function () { + $response = $this->get(route('auth.google.redirect')); + + // Should redirect to Google OAuth, not 404 + $response->assertRedirect(); +}); + +test('google auth callback route exists', function () { + $response = $this->get(route('auth.google.callback')); + + // Should redirect to login on failure (no OAuth code), not 404 + $response->assertRedirect(route('login')); +}); diff --git a/tests/Feature/Social/FacebookControllerTest.php b/tests/Feature/Social/FacebookControllerTest.php index d95cb690..abb0d747 100644 --- a/tests/Feature/Social/FacebookControllerTest.php +++ b/tests/Feature/Social/FacebookControllerTest.php @@ -20,14 +20,16 @@ }); test('facebook connect redirects to oauth provider', function () { + $driverMock = Mockery::mock(); + $driverMock->shouldReceive('usingGraphVersion')->andReturnSelf(); + $driverMock->shouldReceive('setScopes')->andReturnSelf(); + $driverMock->shouldReceive('redirect')->andReturn(Mockery::mock([ + 'getTargetUrl' => 'https://www.facebook.com/v25.0/dialog/oauth?test=1', + ])); + Socialite::shouldReceive('driver') ->with('facebook') - ->andReturn(Mockery::mock([ - 'scopes' => Mockery::self(), - 'redirect' => Mockery::mock([ - 'getTargetUrl' => 'https://www.facebook.com/v21.0/dialog/oauth?test=1', - ]), - ])); + ->andReturn($driverMock); $response = $this->actingAs($this->user) ->withHeader('X-Inertia', 'true') diff --git a/tests/Feature/Social/InstagramControllerTest.php b/tests/Feature/Social/InstagramControllerTest.php index 20b3a2d8..b0117173 100644 --- a/tests/Feature/Social/InstagramControllerTest.php +++ b/tests/Feature/Social/InstagramControllerTest.php @@ -19,14 +19,15 @@ }); test('instagram connect redirects to oauth provider', function () { + $driverMock = Mockery::mock(); + $driverMock->shouldReceive('scopes')->andReturnSelf(); + $driverMock->shouldReceive('redirect')->andReturn(Mockery::mock([ + 'getTargetUrl' => 'https://www.instagram.com/oauth/authorize?test=1', + ])); + Socialite::shouldReceive('driver') ->with('instagram') - ->andReturn(Mockery::mock([ - 'scopes' => Mockery::self(), - 'redirect' => Mockery::mock([ - 'getTargetUrl' => 'https://www.instagram.com/oauth/authorize?test=1', - ]), - ])); + ->andReturn($driverMock); $response = $this->actingAs($this->user) ->withHeader('X-Inertia', 'true') diff --git a/tests/Feature/Social/LinkedInControllerTest.php b/tests/Feature/Social/LinkedInControllerTest.php index 6ced6a71..26aee84a 100644 --- a/tests/Feature/Social/LinkedInControllerTest.php +++ b/tests/Feature/Social/LinkedInControllerTest.php @@ -20,14 +20,15 @@ }); test('linkedin connect redirects to oauth provider', function () { + $driverMock = Mockery::mock(); + $driverMock->shouldReceive('scopes')->andReturnSelf(); + $driverMock->shouldReceive('redirect')->andReturn(Mockery::mock([ + 'getTargetUrl' => 'https://www.linkedin.com/oauth/v2/authorization?test=1', + ])); + Socialite::shouldReceive('driver') ->with('linkedin') - ->andReturn(Mockery::mock([ - 'scopes' => Mockery::self(), - 'redirect' => Mockery::mock([ - 'getTargetUrl' => 'https://www.linkedin.com/oauth/v2/authorization?test=1', - ]), - ])); + ->andReturn($driverMock); $response = $this->actingAs($this->user) ->withHeader('X-Inertia', 'true') diff --git a/tests/Feature/Social/LinkedInPageControllerTest.php b/tests/Feature/Social/LinkedInPageControllerTest.php index e4517af3..ce703bfa 100644 --- a/tests/Feature/Social/LinkedInPageControllerTest.php +++ b/tests/Feature/Social/LinkedInPageControllerTest.php @@ -20,15 +20,16 @@ }); test('linkedin page connect redirects to oauth provider', function () { + $driverMock = Mockery::mock(); + $driverMock->shouldReceive('scopes')->andReturnSelf(); + $driverMock->shouldReceive('with')->andReturnSelf(); + $driverMock->shouldReceive('redirect')->andReturn(Mockery::mock([ + 'getTargetUrl' => 'https://www.linkedin.com/oauth/v2/authorization?test=1', + ])); + Socialite::shouldReceive('driver') ->with('linkedin-openid') - ->andReturn(Mockery::mock([ - 'scopes' => Mockery::self(), - 'with' => Mockery::self(), - 'redirect' => Mockery::mock([ - 'getTargetUrl' => 'https://www.linkedin.com/oauth/v2/authorization?test=1', - ]), - ])); + ->andReturn($driverMock); $response = $this->actingAs($this->user) ->withHeader('X-Inertia', 'true') diff --git a/tests/Feature/Social/PinterestControllerTest.php b/tests/Feature/Social/PinterestControllerTest.php index 1ee6b7e4..0336d742 100644 --- a/tests/Feature/Social/PinterestControllerTest.php +++ b/tests/Feature/Social/PinterestControllerTest.php @@ -19,14 +19,15 @@ }); test('pinterest connect redirects to oauth provider', function () { + $driverMock = Mockery::mock(); + $driverMock->shouldReceive('scopes')->andReturnSelf(); + $driverMock->shouldReceive('redirect')->andReturn(Mockery::mock([ + 'getTargetUrl' => 'https://www.pinterest.com/oauth?test=1', + ])); + Socialite::shouldReceive('driver') ->with('pinterest') - ->andReturn(Mockery::mock([ - 'scopes' => Mockery::self(), - 'redirect' => Mockery::mock([ - 'getTargetUrl' => 'https://www.pinterest.com/oauth?test=1', - ]), - ])); + ->andReturn($driverMock); $response = $this->actingAs($this->user) ->withHeader('X-Inertia', 'true') diff --git a/tests/Feature/Social/TikTokControllerTest.php b/tests/Feature/Social/TikTokControllerTest.php index 707777b2..1df0a79f 100644 --- a/tests/Feature/Social/TikTokControllerTest.php +++ b/tests/Feature/Social/TikTokControllerTest.php @@ -19,14 +19,15 @@ }); test('tiktok connect redirects to oauth provider', function () { + $driverMock = Mockery::mock(); + $driverMock->shouldReceive('scopes')->andReturnSelf(); + $driverMock->shouldReceive('redirect')->andReturn(Mockery::mock([ + 'getTargetUrl' => 'https://www.tiktok.com/v2/auth/authorize?test=1', + ])); + Socialite::shouldReceive('driver') ->with('tiktok') - ->andReturn(Mockery::mock([ - 'scopes' => Mockery::self(), - 'redirect' => Mockery::mock([ - 'getTargetUrl' => 'https://www.tiktok.com/v2/auth/authorize?test=1', - ]), - ])); + ->andReturn($driverMock); $response = $this->actingAs($this->user) ->withHeader('X-Inertia', 'true') diff --git a/tests/Feature/Social/XControllerTest.php b/tests/Feature/Social/XControllerTest.php index 1cdac102..7af106d8 100644 --- a/tests/Feature/Social/XControllerTest.php +++ b/tests/Feature/Social/XControllerTest.php @@ -19,14 +19,15 @@ }); test('x connect redirects to oauth provider', function () { + $driverMock = Mockery::mock(); + $driverMock->shouldReceive('scopes')->andReturnSelf(); + $driverMock->shouldReceive('redirect')->andReturn(Mockery::mock([ + 'getTargetUrl' => 'https://twitter.com/i/oauth2/authorize?test=1', + ])); + Socialite::shouldReceive('driver') ->with('x') - ->andReturn(Mockery::mock([ - 'scopes' => Mockery::self(), - 'redirect' => Mockery::mock([ - 'getTargetUrl' => 'https://twitter.com/i/oauth2/authorize?test=1', - ]), - ])); + ->andReturn($driverMock); $response = $this->actingAs($this->user) ->withHeader('X-Inertia', 'true') diff --git a/tests/Feature/Social/YouTubeControllerTest.php b/tests/Feature/Social/YouTubeControllerTest.php index 21db5603..1d8532f7 100644 --- a/tests/Feature/Social/YouTubeControllerTest.php +++ b/tests/Feature/Social/YouTubeControllerTest.php @@ -20,15 +20,16 @@ }); test('youtube connect redirects to oauth provider', function () { + $driverMock = Mockery::mock(); + $driverMock->shouldReceive('scopes')->andReturnSelf(); + $driverMock->shouldReceive('with')->andReturnSelf(); + $driverMock->shouldReceive('redirect')->andReturn(Mockery::mock([ + 'getTargetUrl' => 'https://accounts.google.com/o/oauth2/v2/auth?test=1', + ])); + Socialite::shouldReceive('driver') ->with('google') - ->andReturn(Mockery::mock([ - 'scopes' => Mockery::self(), - 'with' => Mockery::self(), - 'redirect' => Mockery::mock([ - 'getTargetUrl' => 'https://accounts.google.com/o/oauth2/v2/auth?test=1', - ]), - ])); + ->andReturn($driverMock); $response = $this->actingAs($this->user) ->withHeader('X-Inertia', 'true')