Skip to content

Commit

Permalink
Merge commit from fork
Browse files Browse the repository at this point in the history
  • Loading branch information
joelbutcher authored Dec 20, 2024
1 parent c5828bf commit ae4dc39
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 8 deletions.
47 changes: 47 additions & 0 deletions resources/views/oauth/prompt.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<title>Laravel</title>

<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />

<!-- Styles / Scripts -->
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="font-sans antialiased">
<div class=" min-h-screen bg-gray-100 flex justify-center items-center dark:bg-gray-900">
<div class="w-full sm:max-w-sm bg-white dark:bg-gray-800 overflow-hidden shadow-xl sm:rounded-lg px-6 py-4">
<h2 class="mb-4 font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
Confirm connection of your {{ \JoelButcher\Socialstream\Providers::name($provider) }} account.
</h2>

<form method="POST" action="{{ route('oauth.callback.confirm', $provider) }}">
@csrf
<p class="text-sm text-gray-600 dark:text-gray-400">
@if (config('socialstream.confirmation-prompt'))
{{ config('socialstream.confirmation-prompt') }}
@else
To ensure you are the account owner of this {{ \JoelButcher\Socialstream\Providers::name($provider) }} account,
please confirm or deny the request below to link this provider to your account.
@endif
</p>

<div class="mt-4 flex items-center justify-between">
<button type="submit" name="result" value="deny" class="inline-flex items-center justify-center px-4 py-2 bg-red-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-red-500 active:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150">
Deny
</button>

<button type="submit" name="result" value="confirm" class="inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-200 border border-transparent rounded-md font-semibold text-xs text-white dark:text-gray-800 uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-white focus:bg-gray-700 dark:focus:bg-white active:bg-gray-900 dark:active:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 disabled:opacity-50 transition ease-in-out duration-150">
Confirm
</button>
</div>
</form>
</div>
</div>
</body>
</html>
12 changes: 12 additions & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

use Illuminate\Support\Facades\Route;
use JoelButcher\Socialstream\Http\Controllers\OAuthController;


Route::group(['middleware' => config('socialstream.middleware', ['web'])], function () {
Route::get('/oauth/{provider}/callback/prompt', [OAuthController::class, 'prompt'])->name('oauth.callback.prompt');
Route::post('/oauth/{provider}/callback/confirm', [OAuthController::class, 'confirm'])->name(
'oauth.callback.confirm'
);
});
14 changes: 6 additions & 8 deletions src/Actions/AuthenticateOAuthCallback.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ public function authenticate(string $provider, ProviderUser $providerAccount): S
{
// If the user is authenticated, link the provider to the authenticated user.
if ($user = auth()->user()) {
return $this->link($user, $provider, $providerAccount);
// cache the provider account for 10 mins whilst the user is redirected to the confirmation screen.
cache()->put("socialstream.{$user->id}:$provider.provider", $providerAccount, ttl: new \DateInterval('PT10M'));

return redirect()->route('oauth.callback.prompt', $provider);
}

// Check if the user has an existing OAuth account.
Expand Down Expand Up @@ -198,16 +201,11 @@ function ($request, $next) {
]));
}

/**
* Attempt to link the provider to the authenticated user.
*
* Attempt to link the provider with the authenticated user.
*/
private function link(Authenticatable $user, string $provider, ProviderUser $providerAccount): SocialstreamResponse
public function link(Authenticatable $user, string $provider, ProviderUser $providerAccount): SocialstreamResponse
{
$account = Socialstream::findConnectedAccountForProviderAndId($provider, $providerAccount->getId());

if ($account && $user?->id !== $account->user_id) {
if ($account && $user->id !== $account->user_id) {
event(new OAuthProviderLinkFailed($user, $provider, $account, $providerAccount));

$this->flashError(
Expand Down
62 changes: 62 additions & 0 deletions src/Http/Controllers/OAuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@

namespace JoelButcher\Socialstream\Http\Controllers;

use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\MessageBag;
use Illuminate\Support\ViewErrorBag;
use JoelButcher\Socialstream\Contracts\AuthenticatesOAuthCallback;
use JoelButcher\Socialstream\Contracts\GeneratesProviderRedirect;
use JoelButcher\Socialstream\Contracts\HandlesInvalidState;
use JoelButcher\Socialstream\Contracts\HandlesOAuthCallbackErrors;
use JoelButcher\Socialstream\Contracts\ResolvesSocialiteUsers;
use JoelButcher\Socialstream\Contracts\SocialstreamResponse;
use JoelButcher\Socialstream\Events\OAuthProviderLinkFailed;
use JoelButcher\Socialstream\Http\Responses\OAuthProviderLinkFailedResponse;
use JoelButcher\Socialstream\Providers;
use Laravel\Jetstream\Jetstream;
use Laravel\Socialite\Two\InvalidStateException;
use Symfony\Component\HttpFoundation\RedirectResponse as SymfonyRedirectResponse;

Expand Down Expand Up @@ -59,4 +67,58 @@ public function callback(Request $request, string $provider): SocialstreamRespon

return $this->authenticator->authenticate($provider, $providerAccount);
}

/**
* Show the oauth confirmation page.
*/
public function prompt(string $provider): View
{
return view('socialstream::oauth.prompt', [
'provider' => $provider,
]);
}

public function confirm(string $provider): SocialstreamResponse|RedirectResponse
{
$user = auth()->user();
$providerAccount = cache()->pull("socialstream.{$user->id}:$provider.provider");

$result = request()->input('result');

if ($result === 'deny') {
event(new OAuthProviderLinkFailed($user, $provider, null, $providerAccount));

$this->flashError(
__('Failed to link :provider account. User denied request.', ['provider' => Providers::name($provider)]),
);

return app(OAuthProviderLinkFailedResponse::class);
}

if (!$providerAccount) {
throw new \DomainException(
message: 'Could not retrieve social provider information.'
);
}

return $this->authenticator->link($user, $provider, $providerAccount);
}

private function flashError(string $error): void
{
if (auth()->check()) {
if (class_exists(Jetstream::class)) {
Session::flash('flash.banner', $error);
Session::flash('flash.bannerStyle', 'danger');

return;
}
}

Session::flash('errors', (new ViewErrorBag())->put(
'default',
new MessageBag(['socialstream' => $error])
));
}

}
1 change: 1 addition & 0 deletions src/SocialstreamServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ private function configureRoutes(): void
'domain' => config('socialstream.domain'),
'prefix' => config('socialstream.prefix', config('socialstream.path')),
], function () {
$this->loadRoutesFrom(path: __DIR__.'/../routes/web.php');
$this->loadRoutesFrom(path: __DIR__.'/../routes/'.config('jetstream.stack', 'livewire').'.php');
});
}
Expand Down

0 comments on commit ae4dc39

Please sign in to comment.