name('login'); Route::get('/register', function () { return redirect('/jabali-panel/register'); }); /* |-------------------------------------------------------------------------- | Two-Factor Authentication Challenge |-------------------------------------------------------------------------- */ Route::get('/jabali-panel/two-factor-challenge', \App\Filament\Jabali\Pages\Auth\TwoFactorChallenge::class) ->middleware('web') ->name('filament.jabali.auth.two-factor-challenge'); Route::get('/jabali-admin/two-factor-challenge', \App\Filament\Admin\Pages\Auth\TwoFactorChallenge::class) ->middleware('web') ->name('filament.admin.auth.two-factor-challenge'); /* |-------------------------------------------------------------------------- | Email Auto-Configuration Routes |-------------------------------------------------------------------------- | | These routes handle automatic email client configuration for: | - Microsoft Outlook (Autodiscover) | - Mozilla Thunderbird (Autoconfig) | - iOS/macOS Mail (Mobile Config Profile) | */ // Microsoft Autodiscover (Outlook, Windows Mail, mobile Exchange clients) Route::match(['get', 'post'], '/autodiscover/autodiscover.xml', [AutoDiscoverController::class, 'discover']); Route::match(['get', 'post'], '/Autodiscover/Autodiscover.xml', [AutoDiscoverController::class, 'discover']); Route::match(['get', 'post'], '/AutoDiscover/AutoDiscover.xml', [AutoDiscoverController::class, 'discover']); // Mozilla Autoconfig (Thunderbird, K-9 Mail, other standards-compliant clients) Route::get('/mail/config-v1.1.xml', [AutoconfigController::class, 'config']); Route::get('/.well-known/autoconfig/mail/config-v1.1.xml', [AutoconfigController::class, 'config']); Route::get('/autoconfig/{domain}/config-v1.1.xml', [AutoconfigController::class, 'configForDomain']); // iOS/macOS Mobile Configuration Profile Route::get('/mail/profile/{domain}', [AutoconfigController::class, 'mobileProfile']); /* |-------------------------------------------------------------------------- | Admin Impersonation |-------------------------------------------------------------------------- | | Allows administrators to login as a user using a one-time token. | Opens in a new tab with a separate session. | */ Route::get('/impersonate/start/{user}', [ImpersonationController::class, 'start']) ->middleware('auth:admin') ->name('impersonate.start'); Route::get('/impersonate/stop', [ImpersonationController::class, 'stop']) ->middleware('auth:web') ->name('impersonate.stop'); Route::get('/impersonate/{token}', [ImpersonationController::class, 'impersonate']) ->name('impersonate'); /* |-------------------------------------------------------------------------- | User Panel Backup Download |-------------------------------------------------------------------------- */ Route::get('/jabali-panel/backup-download', [BackupDownloadController::class, 'download']) ->middleware(['web', 'auth']) ->name('filament.jabali.pages.backup-download'); /* |-------------------------------------------------------------------------- | Admin Panel Backup Download |-------------------------------------------------------------------------- */ Route::get('/jabali-admin/backup-download', [BackupDownloadController::class, 'adminDownload']) ->middleware(['web', 'auth']) ->name('filament.admin.pages.backup-download'); /* |-------------------------------------------------------------------------- | Language Switcher |-------------------------------------------------------------------------- */ Route::get('/language/{locale}', [LanguageController::class, 'switch']) ->name('language.switch'); /* |-------------------------------------------------------------------------- | Webmail SSO |-------------------------------------------------------------------------- | | Generates SSO token and redirects to Roundcube webmail. | Opens in new tab, so uses signed URL for security. | */ Route::get('/webmail-sso/{mailbox}', function (\App\Models\Mailbox $mailbox) { // Verify user owns this mailbox if ($mailbox->user_id !== auth()->id()) { abort(403); } $password = $mailbox->plain_password; if ($password) { // Create SSO token for auto-login $token = bin2hex(random_bytes(32)); $tokenData = [ 'email' => $mailbox->email, 'password' => $password, 'expires' => time() + 300, ]; file_put_contents('/tmp/roundcube_sso_'.$token, json_encode($tokenData)); chmod('/tmp/roundcube_sso_'.$token, 0600); return redirect('/webmail/jabali-sso.php?token='.$token); } $hasPasswordHash = ! empty($mailbox->password_hash); $masterConfigPath = '/etc/jabali/roundcube-sso.conf'; if ($hasPasswordHash && file_exists($masterConfigPath)) { $token = bin2hex(random_bytes(32)); $tokenData = [ 'login_as' => $mailbox->email, 'use_master' => true, 'expires' => time() + 300, ]; file_put_contents('/tmp/roundcube_sso_'.$token, json_encode($tokenData)); chmod('/tmp/roundcube_sso_'.$token, 0600); return redirect('/webmail/jabali-sso.php?token='.$token); } // No stored password - show message about needing to reset password first // This happens after restore when password_encrypted isn't set return response()->view('webmail-password-required', [ 'email' => $mailbox->email, 'mailbox_id' => $mailbox->id, 'has_password_hash' => $hasPasswordHash, ]); })->middleware(['web', 'auth'])->name('webmail.sso');