mirror of
https://github.com/sp-tarkov/forge.git
synced 2025-02-12 20:20:41 -05:00
OAuth Management
Adds a edit-user-profile section to allow a user to remove an OAuth connection from their account when they have a local account password set.
This commit is contained in:
parent
46550b5d8f
commit
746fed1746
@ -65,7 +65,11 @@ class SocialiteController extends Controller
|
|||||||
if ($oauthConnection) {
|
if ($oauthConnection) {
|
||||||
$oauthConnection->update([
|
$oauthConnection->update([
|
||||||
'token' => $providerUser->token,
|
'token' => $providerUser->token,
|
||||||
'refresh_token' => $providerUser->refreshToken ?? null,
|
'refresh_token' => $providerUser->refreshToken ?? '',
|
||||||
|
'nickname' => $providerUser->getNickname() ?? '',
|
||||||
|
'name' => $providerUser->getName() ?? '',
|
||||||
|
'email' => $providerUser->getEmail() ?? '',
|
||||||
|
'avatar' => $providerUser->getAvatar() ?? '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $oauthConnection->user;
|
return $oauthConnection->user;
|
||||||
@ -84,7 +88,11 @@ class SocialiteController extends Controller
|
|||||||
'provider' => $provider,
|
'provider' => $provider,
|
||||||
'provider_id' => $providerUser->getId(),
|
'provider_id' => $providerUser->getId(),
|
||||||
'token' => $providerUser->token,
|
'token' => $providerUser->token,
|
||||||
'refresh_token' => $providerUser->refreshToken ?? null,
|
'refresh_token' => $providerUser->refreshToken ?? '',
|
||||||
|
'nickname' => $providerUser->getNickname() ?? '',
|
||||||
|
'name' => $providerUser->getName() ?? '',
|
||||||
|
'email' => $providerUser->getEmail() ?? '',
|
||||||
|
'avatar' => $providerUser->getAvatar() ?? '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $user;
|
return $user;
|
||||||
|
101
app/Livewire/Profile/ManageOAuthConnections.php
Normal file
101
app/Livewire/Profile/ManageOAuthConnections.php
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Profile;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
use Livewire\Attributes\Locked;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class ManageOAuthConnections extends Component
|
||||||
|
{
|
||||||
|
use AuthorizesRequests;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the current user.
|
||||||
|
*/
|
||||||
|
#[Locked]
|
||||||
|
public $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls the confirmation modal visibility.
|
||||||
|
*/
|
||||||
|
public $confirmingConnectionDeletion = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the ID of the connection to be deleted.
|
||||||
|
*/
|
||||||
|
#[Locked]
|
||||||
|
public $selectedConnectionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The component’s listeners.
|
||||||
|
*/
|
||||||
|
protected $listeners = ['saved' => 'refreshUser'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the component by loading the user’s OAuth connections.
|
||||||
|
*/
|
||||||
|
public function mount(): void
|
||||||
|
{
|
||||||
|
$this->setName('profile.manage-oauth-connections');
|
||||||
|
|
||||||
|
$this->user = auth()->user();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the deletion confirmation.
|
||||||
|
*/
|
||||||
|
public function confirmConnectionDeletion($connectionId): void
|
||||||
|
{
|
||||||
|
$this->confirmingConnectionDeletion = true;
|
||||||
|
$this->selectedConnectionId = $connectionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the selected OAuth connection.
|
||||||
|
*/
|
||||||
|
public function deleteConnection(): void
|
||||||
|
{
|
||||||
|
$connection = $this->user->oauthConnections()->find($this->selectedConnectionId);
|
||||||
|
|
||||||
|
// Ensure the user is authorized to delete the connection.
|
||||||
|
$this->authorize('delete', $connection);
|
||||||
|
|
||||||
|
// The user must have a password set before removing an OAuth connection.
|
||||||
|
if ($this->user->password === null) {
|
||||||
|
$this->addError('password_required', __('You must set a password before removing an OAuth connection.'));
|
||||||
|
$this->confirmingConnectionDeletion = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($connection) {
|
||||||
|
$connection->delete();
|
||||||
|
|
||||||
|
$this->user->refresh();
|
||||||
|
$this->confirmingConnectionDeletion = false;
|
||||||
|
$this->selectedConnectionId = null;
|
||||||
|
|
||||||
|
session()->flash('status', __('OAuth connection removed successfully.'));
|
||||||
|
} else {
|
||||||
|
session()->flash('error', __('OAuth connection not found.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes the user instance.
|
||||||
|
*/
|
||||||
|
public function refreshUser(): void
|
||||||
|
{
|
||||||
|
$this->user->refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the component view.
|
||||||
|
*/
|
||||||
|
public function render(): View
|
||||||
|
{
|
||||||
|
return view('livewire.profile.manage-oauth-connections');
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Hash;
|
|||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
|
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
|
||||||
use Laravel\Jetstream\Http\Livewire\UpdatePasswordForm as JetstreamUpdatePasswordForm;
|
use Laravel\Jetstream\Http\Livewire\UpdatePasswordForm as JetstreamUpdatePasswordForm;
|
||||||
|
use Override;
|
||||||
|
|
||||||
class UpdatePasswordForm extends JetstreamUpdatePasswordForm
|
class UpdatePasswordForm extends JetstreamUpdatePasswordForm
|
||||||
{
|
{
|
||||||
@ -19,6 +20,7 @@ class UpdatePasswordForm extends JetstreamUpdatePasswordForm
|
|||||||
* This method has been overwritten to allow a user that has a null password to set a password for their account
|
* This method has been overwritten to allow a user that has a null password to set a password for their account
|
||||||
* without needing to provide their current password. This is useful for users that have been created using OAuth.
|
* without needing to provide their current password. This is useful for users that have been created using OAuth.
|
||||||
*/
|
*/
|
||||||
|
#[Override]
|
||||||
public function updatePassword(UpdatesUserPasswords $updater): void
|
public function updatePassword(UpdatesUserPasswords $updater): void
|
||||||
{
|
{
|
||||||
$this->resetErrorBag();
|
$this->resetErrorBag();
|
||||||
|
25
app/Policies/OAuthConnectionPolicy.php
Normal file
25
app/Policies/OAuthConnectionPolicy.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\OAuthConnection;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
class OAuthConnectionPolicy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view the model.
|
||||||
|
*/
|
||||||
|
public function view(User $user, OAuthConnection $oauthConnection): bool
|
||||||
|
{
|
||||||
|
return $user->id === $oauthConnection->user_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can delete the model.
|
||||||
|
*/
|
||||||
|
public function delete(User $user, OAuthConnection $oauthConnection): bool
|
||||||
|
{
|
||||||
|
return $user->id === $oauthConnection->user_id && $user->password !== null;
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,10 @@ return new class extends Migration
|
|||||||
$table->string('provider_id');
|
$table->string('provider_id');
|
||||||
$table->string('token')->default('');
|
$table->string('token')->default('');
|
||||||
$table->string('refresh_token')->default('');
|
$table->string('refresh_token')->default('');
|
||||||
|
$table->string('nickname')->default('');
|
||||||
|
$table->string('name')->default('');
|
||||||
|
$table->string('email')->default('');
|
||||||
|
$table->string('avatar')->default('');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
|
||||||
$table->unique(['provider', 'provider_id']);
|
$table->unique(['provider', 'provider_id']);
|
||||||
|
@ -0,0 +1,95 @@
|
|||||||
|
<x-action-section>
|
||||||
|
<x-slot name="title">
|
||||||
|
{{ __('Connected Accounts') }}
|
||||||
|
</x-slot>
|
||||||
|
|
||||||
|
<x-slot name="description">
|
||||||
|
{{ __('Manage your connected OAuth accounts.') }}
|
||||||
|
</x-slot>
|
||||||
|
|
||||||
|
<x-slot name="content">
|
||||||
|
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100">
|
||||||
|
{{ __('You can manage your OAuth connections here') }}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
@if ($user->password === null)
|
||||||
|
<div class="mt-3 max-w-xl text-sm text-gray-600 dark:text-gray-400">
|
||||||
|
<p>{{ __('Before you can remove a connection you must have an account password set.') }}</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if (session()->has('status'))
|
||||||
|
<div class="mt-3 font-medium text-sm text-green-600 dark:text-green-400">
|
||||||
|
{{ session('status') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if (session()->has('error'))
|
||||||
|
<div class="mt-3 font-medium text-sm text-red-600 dark:text-red-400">
|
||||||
|
{{ session('error') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="mt-5 space-y-6">
|
||||||
|
@forelse ($user->oauthConnections as $connection)
|
||||||
|
<div class="flex items-center text-gray-600 dark:text-gray-400">
|
||||||
|
<div>
|
||||||
|
@switch ($connection->provider)
|
||||||
|
@case ('discord')
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="w-4 h-4" viewBox="0 0 16 16">
|
||||||
|
<path d="M13.545 2.907a13.2 13.2 0 0 0-3.257-1.011.05.05 0 0 0-.052.025c-.141.25-.297.577-.406.833a12.2 12.2 0 0 0-3.658 0 8 8 0 0 0-.412-.833.05.05 0 0 0-.052-.025c-1.125.194-2.22.534-3.257 1.011a.04.04 0 0 0-.021.018C.356 6.024-.213 9.047.066 12.032q.003.022.021.037a13.3 13.3 0 0 0 3.995 2.02.05.05 0 0 0 .056-.019q.463-.63.818-1.329a.05.05 0 0 0-.01-.059l-.018-.011a9 9 0 0 1-1.248-.595.05.05 0 0 1-.02-.066l.015-.019q.127-.095.248-.195a.05.05 0 0 1 .051-.007c2.619 1.196 5.454 1.196 8.041 0a.05.05 0 0 1 .053.007q.121.1.248.195a.05.05 0 0 1-.004.085 8 8 0 0 1-1.249.594.05.05 0 0 0-.03.03.05.05 0 0 0 .003.041c.24.465.515.909.817 1.329a.05.05 0 0 0 .056.019 13.2 13.2 0 0 0 4.001-2.02.05.05 0 0 0 .021-.037c.334-3.451-.559-6.449-2.366-9.106a.03.03 0 0 0-.02-.019m-8.198 7.307c-.789 0-1.438-.724-1.438-1.612s.637-1.613 1.438-1.613c.807 0 1.45.73 1.438 1.613 0 .888-.637 1.612-1.438 1.612m5.316 0c-.788 0-1.438-.724-1.438-1.612s.637-1.613 1.438-1.613c.807 0 1.451.73 1.438 1.613 0 .888-.631 1.612-1.438 1.612"/>
|
||||||
|
</svg>
|
||||||
|
@break
|
||||||
|
@default
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244" />
|
||||||
|
</svg>
|
||||||
|
@endswitch
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">
|
||||||
|
<div class="text-sm text-gray-600 dark:text-gray-400">
|
||||||
|
{{ ucfirst($connection->provider) }} - {{ $connection->name }} - {{ $connection->email }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-gray-500">
|
||||||
|
{{ __('Connected') }} {{ $connection->created_at->format('M d, Y') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-auto">
|
||||||
|
@can('delete', $connection)
|
||||||
|
<x-danger-button wire:click="confirmConnectionDeletion({{ $connection->id }})" wire:loading.attr="disabled">
|
||||||
|
{{ __('Remove') }}
|
||||||
|
</x-danger-button>
|
||||||
|
@endcan
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@empty
|
||||||
|
<div class="text-sm text-gray-600 dark:text-gray-400">
|
||||||
|
{{ __('You have no connected accounts.') }}
|
||||||
|
</div>
|
||||||
|
@endforelse
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Confirmation Modal -->
|
||||||
|
<x-dialog-modal wire:model="confirmingConnectionDeletion">
|
||||||
|
<x-slot name="title">
|
||||||
|
{{ __('Remove Connected Account') }}
|
||||||
|
</x-slot>
|
||||||
|
|
||||||
|
<x-slot name="content">
|
||||||
|
{{ __('Are you sure you want to remove this connected account? This action cannot be undone.') }}
|
||||||
|
</x-slot>
|
||||||
|
|
||||||
|
<x-slot name="footer">
|
||||||
|
<x-secondary-button wire:click="$toggle('confirmingConnectionDeletion')" wire:loading.attr="disabled">
|
||||||
|
{{ __('Cancel') }}
|
||||||
|
</x-secondary-button>
|
||||||
|
|
||||||
|
<x-danger-button class="ms-3" wire:click="deleteConnection" wire:loading.attr="disabled">
|
||||||
|
{{ __('Remove') }}
|
||||||
|
</x-danger-button>
|
||||||
|
</x-slot>
|
||||||
|
</x-dialog-modal>
|
||||||
|
</x-slot>
|
||||||
|
</x-action-section>
|
@ -29,6 +29,12 @@
|
|||||||
<x-section-border />
|
<x-section-border />
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
{{-- OAuth Management --}}
|
||||||
|
<div class="mt-10 sm:mt-0">
|
||||||
|
@livewire('profile.manage-oauth-connections')
|
||||||
|
</div>
|
||||||
|
<x-section-border />
|
||||||
|
|
||||||
@if (config('session.driver') === 'database')
|
@if (config('session.driver') === 'database')
|
||||||
<div class="mt-10 sm:mt-0">
|
<div class="mt-10 sm:mt-0">
|
||||||
@livewire('profile.logout-other-browser-sessions-form')
|
@livewire('profile.logout-other-browser-sessions-form')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user