浏览代码

Move debug information to the admin section - Closes #303

Bubka 1 年之前
父节点
当前提交
21fa77f348

+ 8 - 20
app/Http/Controllers/SystemController.php

@@ -34,27 +34,15 @@ class SystemController extends Controller
         $infos['common']['Operating system'] = PHP_OS;
         $infos['common']['interface']        = PHP_SAPI;
         // Auth & Security infos
-        if (! is_null($request->user())) {
-            $infos['common']['Auth guard'] = config('auth.defaults.guard');
-            if ($infos['common']['Auth guard'] === 'reverse-proxy-guard') {
-                $infos['common']['Auth proxy logout url']       = config('2fauth.config.proxyLogoutUrl');
-                $infos['common']['Auth proxy header for user']  = config('auth.auth_proxy_headers.user');
-                $infos['common']['Auth proxy header for email'] = config('auth.auth_proxy_headers.email');
-            }
-            $infos['common']['webauthn user verification'] = config('webauthn.user_verification');
-            $infos['common']['Trusted proxies']            = config('2fauth.config.trustedProxies') ?: 'none';
-
-            // Admin settings
-            if ($request->user()->isAdministrator()) {
-                $infos['admin_settings']['useEncryption']  = Settings::get('useEncryption');
-                $infos['admin_settings']['lastRadarScan']  = Carbon::parse(Settings::get('lastRadarScan'))->format('Y-m-d H:i:s');
-                $infos['admin_settings']['checkForUpdate'] = Settings::get('checkForUpdate');
-            }
-        }
-        // User info
-        if ($request->user()) {
-            $infos['user_preferences'] = $request->user()->preferences->toArray();
+        $infos['common']['Auth guard'] = config('auth.defaults.guard');
+        if ($infos['common']['Auth guard'] === 'reverse-proxy-guard') {
+            $infos['common']['Auth proxy logout url']       = config('2fauth.config.proxyLogoutUrl');
+            $infos['common']['Auth proxy header for user']  = config('auth.auth_proxy_headers.user');
+            $infos['common']['Auth proxy header for email'] = config('auth.auth_proxy_headers.email');
         }
+        $infos['common']['webauthn user verification'] = config('webauthn.user_verification');
+        $infos['common']['Trusted proxies']            = config('2fauth.config.trustedProxies') ?: 'none';
+        $infos['common']['lastRadarScan']              = Carbon::parse(Settings::get('lastRadarScan'))->format('Y-m-d H:i:s');
 
         return response()->json($infos);
     }

+ 0 - 56
resources/js/views/About.vue

@@ -1,35 +1,9 @@
 <script setup>
-    import systemService from '@/services/systemService'
     import { UseColorMode } from '@vueuse/components'
-    import CopyButton from '@/components/CopyButton.vue'
 
     const $2fauth = inject('2fauth')
     const router = useRouter()
-
     const returnTo = router.options.history.state.back
-    const infos = ref()
-    const listInfos = ref(null)
-    const userPreferences = ref(false)
-    const listUserPreferences = ref(null)
-    const adminSettings = ref(false)
-    const listAdminSettings = ref(null)
-
-    onMounted(() => {
-        systemService.getSystemInfos({returnError: true}).then(response => {
-            infos.value = response.data.common
-
-            if (response.data.admin_settings) {
-                adminSettings.value = response.data.admin_settings
-            }
-
-            if (response.data.user_preferences) {
-                userPreferences.value = response.data.user_preferences
-            }
-        })
-        .catch(() => {
-            infos.value = null
-        })
-    })
 </script>
 
 <template>
@@ -87,36 +61,6 @@
                 <li>{{ $t('commons.logos_by') }}&nbsp;<a href="https://2fa.directory/">2FA Directory</a>&nbsp;<a class="is-size-7" href="https://github.com/2factorauth/twofactorauth/blob/master/LICENSE.md">(MIT License)</a></li>
             </ul>
         </p>
-        <h2 class="title is-5 has-text-grey-light">
-            {{ $t('commons.environment') }}
-        </h2>
-        <div v-if="infos" class="about-debug box is-family-monospace is-size-7">
-            <CopyButton id="btnCopyEnvVars" :token="listInfos?.innerText" />
-            <ul ref="listInfos" id="listInfos">
-                <li v-for="(value, key) in infos" :value="value" :key="key"><b>{{key}}</b>: {{value}}</li>
-            </ul>
-        </div>
-        <div v-else-if="infos === null" class="about-debug box is-family-monospace is-size-7 has-text-warning-dark">
-            {{ $t('errors.error_during_data_fetching') }}
-        </div>
-        <h2 v-if="adminSettings" class="title is-5 has-text-grey-light">
-            {{ $t('settings.admin_settings') }}
-        </h2>
-        <div v-if="adminSettings" class="about-debug box is-family-monospace is-size-7">
-            <CopyButton id="btnCopyAdminSettings" :token="listAdminSettings?.innerText" />
-            <ul ref="listAdminSettings" id="listAdminSettings">
-                <li v-for="(value, setting) in adminSettings" :value="value" :key="setting"><b>{{setting}}</b>: {{value}}</li>
-            </ul>
-        </div>
-        <h2 v-if="userPreferences" class="title is-5 has-text-grey-light">
-            {{ $t('settings.user_preferences') }}
-        </h2>
-        <div v-if="userPreferences" class="about-debug box is-family-monospace is-size-7">
-            <CopyButton id="btnCopyUserPreferences" :token="listUserPreferences?.innerText" />
-            <ul ref="listUserPreferences" id="listUserPreferences">
-                <li v-for="(value, preference) in userPreferences" :value="value" :key="preference"><b>{{preference}}</b>: {{value}}</li>
-            </ul>
-        </div>
         <!-- footer -->
         <VueFooter :showButtons="true">
             <ButtonBackCloseCancel :returnTo="{ path: returnTo }" action="back" />

+ 26 - 0
resources/js/views/admin/AppSetup.vue

@@ -1,15 +1,20 @@
 <script setup>
     import AdminTabs from '@/layouts/AdminTabs.vue'
     import appSettingService from '@/services/appSettingService'
+    import systemService from '@/services/systemService'
     import { useAppSettingsStore } from '@/stores/appSettings'
     import { useNotifyStore } from '@/stores/notify'
     import VersionChecker from '@/components/VersionChecker.vue'
+    import CopyButton from '@/components/CopyButton.vue'
 
     const $2fauth = inject('2fauth')
     const notify = useNotifyStore()
     const appSettings = useAppSettingsStore()
     const returnTo = useStorage($2fauth.prefix + 'returnTo', 'accounts')
 
+    const infos = ref()
+    const listInfos = ref(null)
+
     /**
      * Saves a setting on the backend
      * @param {string} preference 
@@ -27,6 +32,15 @@
         }
     })
 
+    onMounted(() => {
+        systemService.getSystemInfos({returnError: true}).then(response => {
+            infos.value = response.data.common
+        })
+        .catch(() => {
+            infos.value = null
+        })
+    })
+
 </script>
 
 <template>
@@ -48,6 +62,18 @@
                     <!-- disable SSO registration -->
                     <FormCheckbox v-model="appSettings.enableSso" @update:model-value="val => saveSetting('enableSso', val)" fieldName="enableSso" label="admin.forms.enable_sso.label" help="admin.forms.enable_sso.help" />
                 </form>
+                <h4 class="title is-4 pt-5 has-text-grey-light">{{ $t('commons.environment') }}</h4>
+                <div v-if="infos" class="about-debug box is-family-monospace is-size-7">
+                    <CopyButton id="btnCopyEnvVars" :token="listInfos?.innerText" />
+                    <ul ref="listInfos" id="listInfos">
+                        <li v-for="(value, preference) in infos" :value="value" :key="preference">
+                            <b>{{ preference }}</b>: <span class="has-text-grey">{{ value }}</span>
+                        </li>
+                    </ul>
+                </div>
+                <div v-else-if="infos === null" class="about-debug box is-family-monospace is-size-7 has-text-warning-dark">
+                    {{ $t('errors.error_during_data_fetching') }}
+                </div>
             </FormWrapper>
         </div>
         <VueFooter :showButtons="true">

+ 8 - 1
routes/web.php

@@ -77,7 +77,14 @@ Route::get('refresh-csrf', function () {
     return csrf_token();
 });
 
-Route::get('infos', [SystemController::class, 'infos'])->name('system.infos');
+
+/**
+ * Routes protected by an authentication guard and restricted to administrators
+ */
+Route::group(['middleware' => ['behind-auth', 'admin']], function () {   
+    Route::get('infos', [SystemController::class, 'infos'])->name('system.infos');
+});
+
 Route::get('latestRelease', [SystemController::class, 'latestRelease'])->name('system.latestRelease');
 
 /**

+ 29 - 58
tests/Feature/Http/SystemControllerTest.php

@@ -15,12 +15,12 @@ use Tests\FeatureTestCase;
 #[CoversClass(SystemController::class)]
 class SystemControllerTest extends FeatureTestCase
 {
-    use WithoutMiddleware;
+    //use WithoutMiddleware;
 
     /**
      * @var \App\Models\User|\Illuminate\Contracts\Auth\Authenticatable
      */
-    protected $user;
+    protected $user, $admin;
 
     /**
      * @test
@@ -30,85 +30,55 @@ class SystemControllerTest extends FeatureTestCase
         parent::setUp();
 
         $this->user = User::factory()->create();
+        $this->admin = User::factory()->administrator()->create();
     }
 
     /**
      * @test
      */
-    public function test_infos_returns_only_base_collection()
+    public function test_infos_returns_unauthorized()
     {
         $response = $this->json('GET', '/infos')
-            ->assertOk()
-            ->assertJsonStructure([
-                'common' => [
-                    'Date',
-                    'userAgent',
-                    'Version',
-                    'Environment',
-                    'Install path',
-                    'Debug',
-                    'Cache driver',
-                    'Log channel',
-                    'Log level',
-                    'DB driver',
-                    'PHP version',
-                    'Operating system',
-                    'interface',
-                ],
-            ])
-            ->assertJsonMissing([
-                'user_preferences',
-                'admin_settings',
-            ]);
+            ->assertUnauthorized();
     }
 
     /**
      * @test
      */
-    public function test_infos_returns_user_preferences_when_signed_in()
+    public function test_infos_returns_forbidden()
     {
         $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/infos')
-            ->assertOk()
-            ->assertJsonStructure([
-                'user_preferences' => [
-                    'showOtpAsDot',
-                    'closeOtpOnCopy',
-                    'copyOtpOnDisplay',
-                    'useBasicQrcodeReader',
-                    'displayMode',
-                    'showAccountsIcons',
-                    'kickUserAfter',
-                    'activeGroup',
-                    'rememberActiveGroup',
-                    'defaultGroup',
-                    'defaultCaptureMode',
-                    'useDirectCapture',
-                    'useWebauthnOnly',
-                    'getOfficialIcons',
-                    'lang',
-                ],
-            ]);
+            ->assertForbidden();
     }
 
     /**
      * @test
      */
-    public function test_infos_returns_admin_settings_when_signed_in_as_admin()
+    public function test_infos_returns_only_base_collection()
     {
-        /**
-         * @var \App\Models\User|\Illuminate\Contracts\Auth\Authenticatable
-         */
-        $admin = User::factory()->administrator()->create();
-
-        $response = $this->actingAs($admin, 'api-guard')
+        $response = $this->actingAs($this->admin, 'api-guard')
             ->json('GET', '/infos')
             ->assertOk()
             ->assertJsonStructure([
-                'admin_settings' => [
-                    'useEncryption',
-                    'lastRadarScan',
-                    'checkForUpdate',
+                'common' => [
+                    'Date',
+                    'userAgent',
+                    'Version',
+                    'Environment',
+                    'Install path',
+                    'Debug',
+                    'Cache driver',
+                    'Log channel',
+                    'Log level',
+                    'DB driver',
+                    'PHP version',
+                    'Operating system',
+                    'interface',
+                    'Auth guard',
+                    'webauthn user verification',
+                    'Trusted proxies',
+                    'lastRadarScan'
                 ],
             ]);
     }
@@ -118,11 +88,12 @@ class SystemControllerTest extends FeatureTestCase
      */
     public function test_infos_returns_proxy_collection_when_signed_in_behind_proxy()
     {
-        $response = $this->actingAs($this->user, 'reverse-proxy-guard')
+        $response = $this->actingAs($this->admin, 'reverse-proxy-guard')
             ->json('GET', '/infos')
             ->assertOk()
             ->assertJsonStructure([
                 'common' => [
+                    'Auth proxy logout url',
                     'Auth proxy header for user',
                     'Auth proxy header for email',
                 ],