|
12 | 12 | use App\Models\UserDownload; |
13 | 13 | use App\Models\UserRequest; |
14 | 14 | use Illuminate\Contracts\View\View; |
| 15 | +use Illuminate\Http\JsonResponse; |
15 | 16 | use Illuminate\Http\RedirectResponse; |
16 | 17 | use Illuminate\Http\Request; |
| 18 | +use Illuminate\Support\Facades\Auth; |
17 | 19 | use Illuminate\Support\Facades\Log; |
| 20 | +use Spatie\LaravelPasskeys\Models\Passkey; |
18 | 21 | use Spatie\Permission\Models\Role; |
19 | 22 |
|
20 | 23 | class AdminUserController extends BasePageController |
@@ -148,7 +151,7 @@ public function edit(Request $request) |
148 | 151 | // Check if role is changing and get stack preference |
149 | 152 | $roleChanged = $editedUser->roles_id != $request->input('role'); |
150 | 153 | $stackRole = $request->input('stack_role') ? true : false; // Check if checkbox is checked |
151 | | - $changedBy = auth()->check() ? auth()->id() : null; |
| 154 | + $changedBy = Auth::check() ? Auth::id() : null; |
152 | 155 |
|
153 | 156 | // CRITICAL: Capture the ORIGINAL rolechangedate BEFORE any updates |
154 | 157 | // This is needed for accurate role history tracking |
@@ -269,6 +272,8 @@ public function edit(Request $request) |
269 | 272 |
|
270 | 273 | // Add daily API and download counts |
271 | 274 | if ($user) { |
| 275 | + $user->load('passkeys'); |
| 276 | + |
272 | 277 | try { |
273 | 278 | $user->daily_api_count = UserRequest::getApiRequests($user->id); |
274 | 279 | $user->daily_download_count = UserDownload::getDownloadRequests($user->id); |
@@ -349,4 +354,63 @@ public function verify(Request $request): RedirectResponse |
349 | 354 |
|
350 | 355 | return redirect()->back()->with('error', 'User is invalid'); |
351 | 356 | } |
| 357 | + |
| 358 | + public function destroyPasskey(Request $request, Passkey $passkey): RedirectResponse|JsonResponse |
| 359 | + { |
| 360 | + $targetUser = $passkey->authenticatable; |
| 361 | + $targetUserId = $targetUser?->id; |
| 362 | + $targetUsername = $targetUser?->username; |
| 363 | + $passkeyName = $passkey->name; |
| 364 | + |
| 365 | + $passkey->delete(); |
| 366 | + |
| 367 | + Log::channel('admin')->info('Admin deleted user passkey', [ |
| 368 | + 'admin_user_id' => Auth::id(), |
| 369 | + 'target_user_id' => $targetUserId, |
| 370 | + 'target_username' => $targetUsername, |
| 371 | + 'passkey_id' => $passkey->id, |
| 372 | + 'passkey_name' => $passkeyName, |
| 373 | + ]); |
| 374 | + |
| 375 | + if ($request->expectsJson()) { |
| 376 | + return response()->json(['ok' => true]); |
| 377 | + } |
| 378 | + |
| 379 | + $redirectUrl = $targetUserId |
| 380 | + ? 'admin/user-edit?id='.$targetUserId |
| 381 | + : 'admin/user-list'; |
| 382 | + |
| 383 | + return redirect()->to($redirectUrl)->with('success', 'Passkey deleted successfully.'); |
| 384 | + } |
| 385 | + |
| 386 | + public function wipePasskeys(Request $request): RedirectResponse|JsonResponse |
| 387 | + { |
| 388 | + $validated = $request->validate([ |
| 389 | + 'user_id' => ['required', 'integer', 'exists:users,id'], |
| 390 | + 'confirmation' => ['required', 'string', 'in:WIPE'], |
| 391 | + ]); |
| 392 | + |
| 393 | + $target = User::findOrFail((int) $validated['user_id']); |
| 394 | + $wipedCount = $target->passkeys()->count(); |
| 395 | + $target->passkeys()->delete(); |
| 396 | + |
| 397 | + Log::channel('admin')->warning('Admin wiped user passkeys', [ |
| 398 | + 'admin_user_id' => Auth::id(), |
| 399 | + 'target_user_id' => $target->id, |
| 400 | + 'target_username' => $target->username, |
| 401 | + 'wiped_count' => $wipedCount, |
| 402 | + ]); |
| 403 | + |
| 404 | + $message = "{$wipedCount} passkeys removed from {$target->username}. They can now regain access with their password or an admin-issued reset."; |
| 405 | + |
| 406 | + if ($request->expectsJson()) { |
| 407 | + return response()->json([ |
| 408 | + 'ok' => true, |
| 409 | + 'wiped_count' => $wipedCount, |
| 410 | + 'message' => $message, |
| 411 | + ]); |
| 412 | + } |
| 413 | + |
| 414 | + return redirect()->to('admin/user-edit?id='.$target->id)->with('success', $message); |
| 415 | + } |
352 | 416 | } |
0 commit comments