mirror of
https://github.com/Bubka/2FAuth.git
synced 2025-06-20 11:47:53 +02:00
Move debug information to the admin section - Closes #303
This commit is contained in:
parent
ee4b21eab2
commit
21fa77f348
@ -34,7 +34,6 @@ class SystemController extends Controller
|
|||||||
$infos['common']['Operating system'] = PHP_OS;
|
$infos['common']['Operating system'] = PHP_OS;
|
||||||
$infos['common']['interface'] = PHP_SAPI;
|
$infos['common']['interface'] = PHP_SAPI;
|
||||||
// Auth & Security infos
|
// Auth & Security infos
|
||||||
if (! is_null($request->user())) {
|
|
||||||
$infos['common']['Auth guard'] = config('auth.defaults.guard');
|
$infos['common']['Auth guard'] = config('auth.defaults.guard');
|
||||||
if ($infos['common']['Auth guard'] === 'reverse-proxy-guard') {
|
if ($infos['common']['Auth guard'] === 'reverse-proxy-guard') {
|
||||||
$infos['common']['Auth proxy logout url'] = config('2fauth.config.proxyLogoutUrl');
|
$infos['common']['Auth proxy logout url'] = config('2fauth.config.proxyLogoutUrl');
|
||||||
@ -43,18 +42,7 @@ class SystemController extends Controller
|
|||||||
}
|
}
|
||||||
$infos['common']['webauthn user verification'] = config('webauthn.user_verification');
|
$infos['common']['webauthn user verification'] = config('webauthn.user_verification');
|
||||||
$infos['common']['Trusted proxies'] = config('2fauth.config.trustedProxies') ?: 'none';
|
$infos['common']['Trusted proxies'] = config('2fauth.config.trustedProxies') ?: 'none';
|
||||||
|
$infos['common']['lastRadarScan'] = Carbon::parse(Settings::get('lastRadarScan'))->format('Y-m-d H:i:s');
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json($infos);
|
return response()->json($infos);
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import systemService from '@/services/systemService'
|
|
||||||
import { UseColorMode } from '@vueuse/components'
|
import { UseColorMode } from '@vueuse/components'
|
||||||
import CopyButton from '@/components/CopyButton.vue'
|
|
||||||
|
|
||||||
const $2fauth = inject('2fauth')
|
const $2fauth = inject('2fauth')
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const returnTo = router.options.history.state.back
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -87,36 +61,6 @@
|
|||||||
<li>{{ $t('commons.logos_by') }} <a href="https://2fa.directory/">2FA Directory</a> <a class="is-size-7" href="https://github.com/2factorauth/twofactorauth/blob/master/LICENSE.md">(MIT License)</a></li>
|
<li>{{ $t('commons.logos_by') }} <a href="https://2fa.directory/">2FA Directory</a> <a class="is-size-7" href="https://github.com/2factorauth/twofactorauth/blob/master/LICENSE.md">(MIT License)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</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 -->
|
<!-- footer -->
|
||||||
<VueFooter :showButtons="true">
|
<VueFooter :showButtons="true">
|
||||||
<ButtonBackCloseCancel :returnTo="{ path: returnTo }" action="back" />
|
<ButtonBackCloseCancel :returnTo="{ path: returnTo }" action="back" />
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import AdminTabs from '@/layouts/AdminTabs.vue'
|
import AdminTabs from '@/layouts/AdminTabs.vue'
|
||||||
import appSettingService from '@/services/appSettingService'
|
import appSettingService from '@/services/appSettingService'
|
||||||
|
import systemService from '@/services/systemService'
|
||||||
import { useAppSettingsStore } from '@/stores/appSettings'
|
import { useAppSettingsStore } from '@/stores/appSettings'
|
||||||
import { useNotifyStore } from '@/stores/notify'
|
import { useNotifyStore } from '@/stores/notify'
|
||||||
import VersionChecker from '@/components/VersionChecker.vue'
|
import VersionChecker from '@/components/VersionChecker.vue'
|
||||||
|
import CopyButton from '@/components/CopyButton.vue'
|
||||||
|
|
||||||
const $2fauth = inject('2fauth')
|
const $2fauth = inject('2fauth')
|
||||||
const notify = useNotifyStore()
|
const notify = useNotifyStore()
|
||||||
const appSettings = useAppSettingsStore()
|
const appSettings = useAppSettingsStore()
|
||||||
const returnTo = useStorage($2fauth.prefix + 'returnTo', 'accounts')
|
const returnTo = useStorage($2fauth.prefix + 'returnTo', 'accounts')
|
||||||
|
|
||||||
|
const infos = ref()
|
||||||
|
const listInfos = ref(null)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves a setting on the backend
|
* Saves a setting on the backend
|
||||||
* @param {string} preference
|
* @param {string} preference
|
||||||
@ -27,6 +32,15 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
systemService.getSystemInfos({returnError: true}).then(response => {
|
||||||
|
infos.value = response.data.common
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
infos.value = null
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -48,6 +62,18 @@
|
|||||||
<!-- disable SSO registration -->
|
<!-- 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" />
|
<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>
|
</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>
|
</FormWrapper>
|
||||||
</div>
|
</div>
|
||||||
<VueFooter :showButtons="true">
|
<VueFooter :showButtons="true">
|
||||||
|
@ -77,7 +77,14 @@ Route::get('refresh-csrf', function () {
|
|||||||
return csrf_token();
|
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');
|
Route::get('latestRelease', [SystemController::class, 'latestRelease'])->name('system.latestRelease');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,12 +15,12 @@ use Tests\FeatureTestCase;
|
|||||||
#[CoversClass(SystemController::class)]
|
#[CoversClass(SystemController::class)]
|
||||||
class SystemControllerTest extends FeatureTestCase
|
class SystemControllerTest extends FeatureTestCase
|
||||||
{
|
{
|
||||||
use WithoutMiddleware;
|
//use WithoutMiddleware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \App\Models\User|\Illuminate\Contracts\Auth\Authenticatable
|
* @var \App\Models\User|\Illuminate\Contracts\Auth\Authenticatable
|
||||||
*/
|
*/
|
||||||
protected $user;
|
protected $user, $admin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
@ -30,6 +30,26 @@ class SystemControllerTest extends FeatureTestCase
|
|||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
$this->user = User::factory()->create();
|
$this->user = User::factory()->create();
|
||||||
|
$this->admin = User::factory()->administrator()->create();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function test_infos_returns_unauthorized()
|
||||||
|
{
|
||||||
|
$response = $this->json('GET', '/infos')
|
||||||
|
->assertUnauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function test_infos_returns_forbidden()
|
||||||
|
{
|
||||||
|
$response = $this->actingAs($this->user, 'api-guard')
|
||||||
|
->json('GET', '/infos')
|
||||||
|
->assertForbidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,7 +57,8 @@ class SystemControllerTest extends FeatureTestCase
|
|||||||
*/
|
*/
|
||||||
public function test_infos_returns_only_base_collection()
|
public function test_infos_returns_only_base_collection()
|
||||||
{
|
{
|
||||||
$response = $this->json('GET', '/infos')
|
$response = $this->actingAs($this->admin, 'api-guard')
|
||||||
|
->json('GET', '/infos')
|
||||||
->assertOk()
|
->assertOk()
|
||||||
->assertJsonStructure([
|
->assertJsonStructure([
|
||||||
'common' => [
|
'common' => [
|
||||||
@ -54,61 +75,10 @@ class SystemControllerTest extends FeatureTestCase
|
|||||||
'PHP version',
|
'PHP version',
|
||||||
'Operating system',
|
'Operating system',
|
||||||
'interface',
|
'interface',
|
||||||
],
|
'Auth guard',
|
||||||
])
|
'webauthn user verification',
|
||||||
->assertJsonMissing([
|
'Trusted proxies',
|
||||||
'user_preferences',
|
'lastRadarScan'
|
||||||
'admin_settings',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
*/
|
|
||||||
public function test_infos_returns_user_preferences_when_signed_in()
|
|
||||||
{
|
|
||||||
$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',
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
*/
|
|
||||||
public function test_infos_returns_admin_settings_when_signed_in_as_admin()
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var \App\Models\User|\Illuminate\Contracts\Auth\Authenticatable
|
|
||||||
*/
|
|
||||||
$admin = User::factory()->administrator()->create();
|
|
||||||
|
|
||||||
$response = $this->actingAs($admin, 'api-guard')
|
|
||||||
->json('GET', '/infos')
|
|
||||||
->assertOk()
|
|
||||||
->assertJsonStructure([
|
|
||||||
'admin_settings' => [
|
|
||||||
'useEncryption',
|
|
||||||
'lastRadarScan',
|
|
||||||
'checkForUpdate',
|
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -118,11 +88,12 @@ class SystemControllerTest extends FeatureTestCase
|
|||||||
*/
|
*/
|
||||||
public function test_infos_returns_proxy_collection_when_signed_in_behind_proxy()
|
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')
|
->json('GET', '/infos')
|
||||||
->assertOk()
|
->assertOk()
|
||||||
->assertJsonStructure([
|
->assertJsonStructure([
|
||||||
'common' => [
|
'common' => [
|
||||||
|
'Auth proxy logout url',
|
||||||
'Auth proxy header for user',
|
'Auth proxy header for user',
|
||||||
'Auth proxy header for email',
|
'Auth proxy header for email',
|
||||||
],
|
],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user