user(); return Inertia::render('settings/profile/Authentication', [ 'sessions' => $this->getSessions($request), 'hasPassword' => (bool) $user->password, 'connectedAccounts' => $this->getConnectedAccounts($user), ]); } public function updatePassword(AuthenticationPasswordRequest $request): RedirectResponse { $request->user()->update([ 'password' => $request->password, ]); return back()->with('flash.success', __('settings.flash.password_updated')); } public function destroyOtherSessions(Request $request): RedirectResponse { $user = $request->user(); if ($user->password) { $request->validate([ 'password' => ['required', 'string', 'current_password'], ]); } else { $request->validate([ 'email_confirmation' => ['required', 'string', Rule::in([$user->email])], ], [ 'email_confirmation.in' => __('settings.authentication.sessions.email_mismatch'), ]); } DB::table(config('session.table', 'sessions')) ->where('user_id', $user->id) ->where('id', '!=', $request->session()->getId()) ->delete(); return back()->with('flash.success', __('settings.authentication.sessions.flash_logged_out')); } public function connectProvider(string $provider): RedirectResponse { abort_unless(in_array($provider, self::PROVIDERS, true), 404); return match ($provider) { 'google' => Socialite::driver('google-auth')->redirect(), 'github' => Socialite::driver('github')->scopes(['read:user', 'user:email'])->redirect(), }; } public function disconnectProvider(Request $request, string $provider): RedirectResponse { abort_unless(in_array($provider, self::PROVIDERS, true), 404); $user = $request->user(); $column = "{$provider}_id"; if (! $user->{$column}) { return back(); } if (! $this->canDisconnect($user, $provider)) { return back()->with('flash.error', __('settings.authentication.providers.flash_cannot_disconnect')); } $user->update([$column => null]); return back()->with('flash.success', __('settings.authentication.providers.flash_disconnected', [ 'provider' => ucfirst($provider), ])); } /** * @return array */ private function getSessions(Request $request): array { if (config('session.driver') !== 'database') { return []; } return collect( DB::table(config('session.table', 'sessions')) ->where('user_id', $request->user()->id) ->orderByDesc('last_activity') ->get() )->map(fn ($session) => [ 'id' => $session->id, 'ip_address' => $session->ip_address, 'user_agent' => $session->user_agent, 'last_active' => Carbon::createFromTimestamp($session->last_activity)->diffForHumans(), 'is_current' => $session->id === $request->session()->getId(), ])->values()->all(); } /** * @return array */ private function getConnectedAccounts(User $user): array { $labels = [ 'google' => 'Google', 'github' => 'GitHub', ]; return collect(self::PROVIDERS)->map(fn (string $provider) => [ 'provider' => $provider, 'label' => $labels[$provider], 'connected' => (bool) $user->{"{$provider}_id"}, 'can_disconnect' => $user->{"{$provider}_id"} && $this->canDisconnect($user, $provider), ])->values()->all(); } private function canDisconnect(User $user, string $provider): bool { $remainingMethods = 0; if ($user->password) { $remainingMethods++; } foreach (self::PROVIDERS as $other) { if ($other === $provider) { continue; } if ($user->{"{$other}_id"}) { $remainingMethods++; } } return $remainingMethods > 0; } }