mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-02-01 18:41:54 +08:00
fix: 修复部分资源未授权访问,删除冗余 Admin 判断逻辑
This commit is contained in:
@@ -40,20 +40,20 @@ pub async fn auth_middleware(
|
|||||||
mut request: Request,
|
mut request: Request,
|
||||||
next: Next,
|
next: Next,
|
||||||
) -> Result<Response, StatusCode> {
|
) -> Result<Response, StatusCode> {
|
||||||
|
let raw_path = request.uri().path();
|
||||||
|
// When this middleware is mounted under /api, Axum strips the prefix for the inner router.
|
||||||
|
// Normalize the path so checks work whether it is mounted or not.
|
||||||
|
let path = raw_path.strip_prefix("/api").unwrap_or(raw_path);
|
||||||
|
|
||||||
// Check if system is initialized
|
// Check if system is initialized
|
||||||
if !state.config.is_initialized() {
|
if !state.config.is_initialized() {
|
||||||
// Allow access to setup endpoints when not initialized
|
// Allow only setup-related endpoints when not initialized
|
||||||
let path = request.uri().path();
|
if is_setup_public_endpoint(path) {
|
||||||
if path.starts_with("/api/setup")
|
|
||||||
|| path == "/api/info"
|
|
||||||
|| path.starts_with("/") && !path.starts_with("/api/")
|
|
||||||
{
|
|
||||||
return Ok(next.run(request).await);
|
return Ok(next.run(request).await);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public endpoints that don't require auth
|
// Public endpoints that don't require auth
|
||||||
let path = request.uri().path();
|
|
||||||
if is_public_endpoint(path) {
|
if is_public_endpoint(path) {
|
||||||
return Ok(next.run(request).await);
|
return Ok(next.run(request).await);
|
||||||
}
|
}
|
||||||
@@ -89,21 +89,14 @@ fn unauthorized_response(message: &str) -> Response {
|
|||||||
|
|
||||||
/// Check if endpoint is public (no auth required)
|
/// Check if endpoint is public (no auth required)
|
||||||
fn is_public_endpoint(path: &str) -> bool {
|
fn is_public_endpoint(path: &str) -> bool {
|
||||||
// Note: paths here are relative to /api since middleware is applied before nest
|
// Note: paths here are relative to /api since middleware is applied within the nested router
|
||||||
matches!(
|
matches!(
|
||||||
path,
|
path,
|
||||||
"/"
|
"/"
|
||||||
| "/auth/login"
|
| "/auth/login"
|
||||||
| "/info"
|
|
||||||
| "/health"
|
| "/health"
|
||||||
| "/setup"
|
| "/setup"
|
||||||
| "/setup/init"
|
| "/setup/init"
|
||||||
// Also check with /api prefix for direct access
|
|
||||||
| "/api/auth/login"
|
|
||||||
| "/api/info"
|
|
||||||
| "/api/health"
|
|
||||||
| "/api/setup"
|
|
||||||
| "/api/setup/init"
|
|
||||||
) || path.starts_with("/assets/")
|
) || path.starts_with("/assets/")
|
||||||
|| path.starts_with("/static/")
|
|| path.starts_with("/static/")
|
||||||
|| path.ends_with(".js")
|
|| path.ends_with(".js")
|
||||||
@@ -112,3 +105,11 @@ fn is_public_endpoint(path: &str) -> bool {
|
|||||||
|| path.ends_with(".png")
|
|| path.ends_with(".png")
|
||||||
|| path.ends_with(".svg")
|
|| path.ends_with(".svg")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Setup-only endpoints allowed before initialization.
|
||||||
|
fn is_setup_public_endpoint(path: &str) -> bool {
|
||||||
|
matches!(
|
||||||
|
path,
|
||||||
|
"/setup" | "/setup/init" | "/devices" | "/stream/codecs"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -465,7 +465,6 @@ pub async fn logout(
|
|||||||
pub struct AuthCheckResponse {
|
pub struct AuthCheckResponse {
|
||||||
pub authenticated: bool,
|
pub authenticated: bool,
|
||||||
pub user: Option<String>,
|
pub user: Option<String>,
|
||||||
pub is_admin: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn auth_check(
|
pub async fn auth_check(
|
||||||
@@ -481,7 +480,6 @@ pub async fn auth_check(
|
|||||||
Json(AuthCheckResponse {
|
Json(AuthCheckResponse {
|
||||||
authenticated: true,
|
authenticated: true,
|
||||||
user: username,
|
user: username,
|
||||||
is_admin: true,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ pub fn create_router(state: Arc<AppState>) -> Router {
|
|||||||
.route("/setup", get(handlers::setup_status))
|
.route("/setup", get(handlers::setup_status))
|
||||||
.route("/setup/init", post(handlers::setup_init));
|
.route("/setup/init", post(handlers::setup_init));
|
||||||
|
|
||||||
// User routes (authenticated users - both regular and admin)
|
// Authenticated routes (all logged-in users)
|
||||||
let user_routes = Router::new()
|
let user_routes = Router::new()
|
||||||
.route("/info", get(handlers::system_info))
|
.route("/info", get(handlers::system_info))
|
||||||
.route("/auth/logout", post(handlers::logout))
|
.route("/auth/logout", post(handlers::logout))
|
||||||
@@ -71,10 +71,6 @@ pub fn create_router(state: Arc<AppState>) -> Router {
|
|||||||
.route("/audio/devices", get(handlers::list_audio_devices))
|
.route("/audio/devices", get(handlers::list_audio_devices))
|
||||||
// Audio WebSocket endpoint
|
// Audio WebSocket endpoint
|
||||||
.route("/ws/audio", any(audio_ws_handler))
|
.route("/ws/audio", any(audio_ws_handler))
|
||||||
;
|
|
||||||
|
|
||||||
// Admin-only routes (require admin privileges)
|
|
||||||
let admin_routes = Router::new()
|
|
||||||
// Configuration management (domain-separated endpoints)
|
// Configuration management (domain-separated endpoints)
|
||||||
.route("/config", get(handlers::config::get_all_config))
|
.route("/config", get(handlers::config::get_all_config))
|
||||||
.route("/config", post(handlers::update_config))
|
.route("/config", post(handlers::update_config))
|
||||||
@@ -199,11 +195,10 @@ pub fn create_router(state: Arc<AppState>) -> Router {
|
|||||||
.route("/terminal", get(handlers::terminal::terminal_index))
|
.route("/terminal", get(handlers::terminal::terminal_index))
|
||||||
.route("/terminal/", get(handlers::terminal::terminal_index))
|
.route("/terminal/", get(handlers::terminal::terminal_index))
|
||||||
.route("/terminal/ws", get(handlers::terminal::terminal_ws))
|
.route("/terminal/ws", get(handlers::terminal::terminal_ws))
|
||||||
.route("/terminal/{*path}", get(handlers::terminal::terminal_proxy))
|
.route("/terminal/{*path}", get(handlers::terminal::terminal_proxy));
|
||||||
;
|
|
||||||
|
|
||||||
// Combine protected routes (user + admin)
|
// Protected routes (all authenticated users)
|
||||||
let protected_routes = Router::new().merge(user_routes).merge(admin_routes);
|
let protected_routes = user_routes;
|
||||||
|
|
||||||
// Stream endpoints (accessible with auth, but typically embedded in pages)
|
// Stream endpoints (accessible with auth, but typically embedded in pages)
|
||||||
let stream_routes = Router::new()
|
let stream_routes = Router::new()
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const authApi = {
|
|||||||
request<{ success: boolean }>('/auth/logout', { method: 'POST' }),
|
request<{ success: boolean }>('/auth/logout', { method: 'POST' }),
|
||||||
|
|
||||||
check: () =>
|
check: () =>
|
||||||
request<{ authenticated: boolean; user?: string; is_admin?: boolean }>('/auth/check'),
|
request<{ authenticated: boolean; user?: string }>('/auth/check'),
|
||||||
|
|
||||||
changePassword: (currentPassword: string, newPassword: string) =>
|
changePassword: (currentPassword: string, newPassword: string) =>
|
||||||
request<{ success: boolean }>('/auth/password', {
|
request<{ success: boolean }>('/auth/password', {
|
||||||
|
|||||||
@@ -52,14 +52,13 @@ const overflowMenuOpen = ref(false)
|
|||||||
const hidBackend = computed(() => (systemStore.hid?.backend ?? '').toLowerCase())
|
const hidBackend = computed(() => (systemStore.hid?.backend ?? '').toLowerCase())
|
||||||
const isCh9329Backend = computed(() => hidBackend.value.includes('ch9329'))
|
const isCh9329Backend = computed(() => hidBackend.value.includes('ch9329'))
|
||||||
const showMsd = computed(() => {
|
const showMsd = computed(() => {
|
||||||
return props.isAdmin && !isCh9329Backend.value
|
return !!systemStore.msd?.available && !isCh9329Backend.value
|
||||||
})
|
})
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
mouseMode?: 'absolute' | 'relative'
|
mouseMode?: 'absolute' | 'relative'
|
||||||
videoMode?: VideoMode
|
videoMode?: VideoMode
|
||||||
ttydRunning?: boolean
|
ttydRunning?: boolean
|
||||||
isAdmin?: boolean
|
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@@ -93,18 +92,16 @@ const extensionOpen = ref(false)
|
|||||||
<VideoConfigPopover
|
<VideoConfigPopover
|
||||||
v-model:open="videoPopoverOpen"
|
v-model:open="videoPopoverOpen"
|
||||||
:video-mode="props.videoMode || 'mjpeg'"
|
:video-mode="props.videoMode || 'mjpeg'"
|
||||||
:is-admin="props.isAdmin"
|
|
||||||
@update:video-mode="emit('update:videoMode', $event)"
|
@update:video-mode="emit('update:videoMode', $event)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Audio Config - Always visible -->
|
<!-- Audio Config - Always visible -->
|
||||||
<AudioConfigPopover v-model:open="audioPopoverOpen" :is-admin="props.isAdmin" />
|
<AudioConfigPopover v-model:open="audioPopoverOpen" />
|
||||||
|
|
||||||
<!-- HID Config - Always visible -->
|
<!-- HID Config - Always visible -->
|
||||||
<HidConfigPopover
|
<HidConfigPopover
|
||||||
v-model:open="hidPopoverOpen"
|
v-model:open="hidPopoverOpen"
|
||||||
:mouse-mode="mouseMode"
|
:mouse-mode="mouseMode"
|
||||||
:is-admin="props.isAdmin"
|
|
||||||
@update:mouse-mode="emit('toggleMouseMode')"
|
@update:mouse-mode="emit('toggleMouseMode')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -125,7 +122,7 @@ const extensionOpen = ref(false)
|
|||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
|
|
||||||
<!-- ATX Power Control - Hidden on small screens -->
|
<!-- ATX Power Control - Hidden on small screens -->
|
||||||
<Popover v-if="props.isAdmin" v-model:open="atxOpen" class="hidden sm:block">
|
<Popover v-model:open="atxOpen" class="hidden sm:block">
|
||||||
<PopoverTrigger as-child>
|
<PopoverTrigger as-child>
|
||||||
<Button variant="ghost" size="sm" class="h-8 gap-1.5 text-xs">
|
<Button variant="ghost" size="sm" class="h-8 gap-1.5 text-xs">
|
||||||
<Power class="h-4 w-4" />
|
<Power class="h-4 w-4" />
|
||||||
@@ -159,8 +156,8 @@ const extensionOpen = ref(false)
|
|||||||
|
|
||||||
<!-- Right side buttons -->
|
<!-- Right side buttons -->
|
||||||
<div class="flex items-center gap-1.5 shrink-0">
|
<div class="flex items-center gap-1.5 shrink-0">
|
||||||
<!-- Extension Menu - Admin only, hidden on small screens -->
|
<!-- Extension Menu - Hidden on small screens -->
|
||||||
<Popover v-if="props.isAdmin" v-model:open="extensionOpen" class="hidden lg:block">
|
<Popover v-model:open="extensionOpen" class="hidden lg:block">
|
||||||
<PopoverTrigger as-child>
|
<PopoverTrigger as-child>
|
||||||
<Button variant="ghost" size="sm" class="h-8 gap-1.5 text-xs">
|
<Button variant="ghost" size="sm" class="h-8 gap-1.5 text-xs">
|
||||||
<Cable class="h-4 w-4" />
|
<Cable class="h-4 w-4" />
|
||||||
@@ -183,8 +180,8 @@ const extensionOpen = ref(false)
|
|||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
||||||
<!-- Settings - Admin only, hidden on small screens -->
|
<!-- Settings - Hidden on small screens -->
|
||||||
<TooltipProvider v-if="props.isAdmin" class="hidden lg:block">
|
<TooltipProvider class="hidden lg:block">
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger as-child>
|
<TooltipTrigger as-child>
|
||||||
<Button variant="ghost" size="sm" class="h-8 gap-1.5 text-xs" @click="router.push('/settings')">
|
<Button variant="ghost" size="sm" class="h-8 gap-1.5 text-xs" @click="router.push('/settings')">
|
||||||
@@ -270,7 +267,7 @@ const extensionOpen = ref(false)
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|
||||||
<!-- ATX - Mobile only -->
|
<!-- ATX - Mobile only -->
|
||||||
<DropdownMenuItem v-if="props.isAdmin" class="sm:hidden" @click="atxOpen = true; overflowMenuOpen = false">
|
<DropdownMenuItem class="sm:hidden" @click="atxOpen = true; overflowMenuOpen = false">
|
||||||
<Power class="h-4 w-4 mr-2" />
|
<Power class="h-4 w-4 mr-2" />
|
||||||
{{ t('actionbar.power') }}
|
{{ t('actionbar.power') }}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
@@ -291,7 +288,6 @@ const extensionOpen = ref(false)
|
|||||||
|
|
||||||
<!-- Extension - Tablet and below -->
|
<!-- Extension - Tablet and below -->
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
v-if="props.isAdmin"
|
|
||||||
class="lg:hidden"
|
class="lg:hidden"
|
||||||
:disabled="!props.ttydRunning"
|
:disabled="!props.ttydRunning"
|
||||||
@click="emit('openTerminal'); overflowMenuOpen = false"
|
@click="emit('openTerminal'); overflowMenuOpen = false"
|
||||||
@@ -301,7 +297,7 @@ const extensionOpen = ref(false)
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|
||||||
<!-- Settings - Tablet and below -->
|
<!-- Settings - Tablet and below -->
|
||||||
<DropdownMenuItem v-if="props.isAdmin" class="lg:hidden" @click="router.push('/settings'); overflowMenuOpen = false">
|
<DropdownMenuItem class="lg:hidden" @click="router.push('/settings'); overflowMenuOpen = false">
|
||||||
<Settings class="h-4 w-4 mr-2" />
|
<Settings class="h-4 w-4 mr-2" />
|
||||||
{{ t('actionbar.settings') }}
|
{{ t('actionbar.settings') }}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ interface AudioDevice {
|
|||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
open: boolean
|
open: boolean
|
||||||
isAdmin?: boolean
|
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@@ -203,11 +202,10 @@ watch(() => props.open, (isOpen) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Device Settings (requires apply) - Admin only -->
|
<!-- Device Settings (requires apply) -->
|
||||||
<template v-if="props.isAdmin">
|
<Separator />
|
||||||
<Separator />
|
|
||||||
|
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<h5 class="text-xs font-medium text-muted-foreground">
|
<h5 class="text-xs font-medium text-muted-foreground">
|
||||||
{{ t('actionbar.audioDeviceSettings') }}
|
{{ t('actionbar.audioDeviceSettings') }}
|
||||||
@@ -311,7 +309,6 @@ watch(() => props.open, (isOpen) => {
|
|||||||
<span>{{ applying ? t('actionbar.applying') : t('common.apply') }}</span>
|
<span>{{ applying ? t('actionbar.applying') : t('common.apply') }}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import { useSystemStore } from '@/stores/system'
|
|||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
open: boolean
|
open: boolean
|
||||||
mouseMode?: 'absolute' | 'relative'
|
mouseMode?: 'absolute' | 'relative'
|
||||||
isAdmin?: boolean
|
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@@ -304,11 +303,10 @@ watch(() => props.open, (isOpen) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- HID Device Settings (Requires Apply) - Admin only -->
|
<!-- HID Device Settings (Requires Apply) -->
|
||||||
<template v-if="props.isAdmin">
|
<Separator />
|
||||||
<Separator />
|
|
||||||
|
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<h5 class="text-xs font-medium text-muted-foreground">{{ t('actionbar.hidDeviceSettings') }}</h5>
|
<h5 class="text-xs font-medium text-muted-foreground">{{ t('actionbar.hidDeviceSettings') }}</h5>
|
||||||
<Button
|
<Button
|
||||||
@@ -393,8 +391,7 @@ watch(() => props.open, (isOpen) => {
|
|||||||
<Loader2 v-if="applying" class="h-3.5 w-3.5 mr-1.5 animate-spin" />
|
<Loader2 v-if="applying" class="h-3.5 w-3.5 mr-1.5 animate-spin" />
|
||||||
<span>{{ applying ? t('actionbar.applying') : t('common.apply') }}</span>
|
<span>{{ applying ? t('actionbar.applying') : t('common.apply') }}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ interface VideoDevice {
|
|||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
open: boolean
|
open: boolean
|
||||||
videoMode: VideoMode
|
videoMode: VideoMode
|
||||||
isAdmin?: boolean
|
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@@ -619,9 +618,7 @@ watch(currentConfig, () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Settings Link - Admin only -->
|
|
||||||
<Button
|
<Button
|
||||||
v-if="props.isAdmin"
|
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
class="w-full h-7 text-xs text-muted-foreground hover:text-foreground justify-start px-0"
|
class="w-full h-7 text-xs text-muted-foreground hover:text-foreground justify-start px-0"
|
||||||
@@ -632,11 +629,10 @@ watch(currentConfig, () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Device Settings Section - Admin only -->
|
<!-- Device Settings Section -->
|
||||||
<template v-if="props.isAdmin">
|
<Separator />
|
||||||
<Separator />
|
|
||||||
|
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<h5 class="text-xs font-medium text-muted-foreground">{{ t('actionbar.deviceSettings') }}</h5>
|
<h5 class="text-xs font-medium text-muted-foreground">{{ t('actionbar.deviceSettings') }}</h5>
|
||||||
<Button
|
<Button
|
||||||
@@ -784,8 +780,7 @@ watch(currentConfig, () => {
|
|||||||
<Loader2 v-if="applying" class="h-3.5 w-3.5 mr-1.5 animate-spin" />
|
<Loader2 v-if="applying" class="h-3.5 w-3.5 mr-1.5 animate-spin" />
|
||||||
<span>{{ applying ? t('actionbar.applying') : t('common.apply') }}</span>
|
<span>{{ applying ? t('actionbar.applying') : t('common.apply') }}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { authApi, systemApi } from '@/api'
|
|||||||
|
|
||||||
export const useAuthStore = defineStore('auth', () => {
|
export const useAuthStore = defineStore('auth', () => {
|
||||||
const user = ref<string | null>(null)
|
const user = ref<string | null>(null)
|
||||||
const isAdmin = ref(false)
|
|
||||||
const isAuthenticated = ref(false)
|
const isAuthenticated = ref(false)
|
||||||
const initialized = ref(false)
|
const initialized = ref(false)
|
||||||
const needsSetup = ref(false)
|
const needsSetup = ref(false)
|
||||||
@@ -30,12 +29,10 @@ export const useAuthStore = defineStore('auth', () => {
|
|||||||
const result = await authApi.check()
|
const result = await authApi.check()
|
||||||
isAuthenticated.value = result.authenticated
|
isAuthenticated.value = result.authenticated
|
||||||
user.value = result.user || null
|
user.value = result.user || null
|
||||||
isAdmin.value = result.is_admin ?? false
|
|
||||||
return result
|
return result
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
isAuthenticated.value = false
|
isAuthenticated.value = false
|
||||||
user.value = null
|
user.value = null
|
||||||
isAdmin.value = false
|
|
||||||
error.value = e instanceof Error ? e.message : 'Not authenticated'
|
error.value = e instanceof Error ? e.message : 'Not authenticated'
|
||||||
if (e instanceof Error) {
|
if (e instanceof Error) {
|
||||||
throw e
|
throw e
|
||||||
@@ -53,13 +50,6 @@ export const useAuthStore = defineStore('auth', () => {
|
|||||||
if (result.success) {
|
if (result.success) {
|
||||||
isAuthenticated.value = true
|
isAuthenticated.value = true
|
||||||
user.value = username
|
user.value = username
|
||||||
// After login, fetch admin status
|
|
||||||
try {
|
|
||||||
const authResult = await authApi.check()
|
|
||||||
isAdmin.value = authResult.is_admin ?? false
|
|
||||||
} catch {
|
|
||||||
isAdmin.value = false
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
error.value = result.message || 'Login failed'
|
error.value = result.message || 'Login failed'
|
||||||
@@ -79,7 +69,6 @@ export const useAuthStore = defineStore('auth', () => {
|
|||||||
} finally {
|
} finally {
|
||||||
isAuthenticated.value = false
|
isAuthenticated.value = false
|
||||||
user.value = null
|
user.value = null
|
||||||
isAdmin.value = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +113,6 @@ export const useAuthStore = defineStore('auth', () => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
user,
|
user,
|
||||||
isAdmin,
|
|
||||||
isAuthenticated,
|
isAuthenticated,
|
||||||
initialized,
|
initialized,
|
||||||
needsSetup,
|
needsSetup,
|
||||||
|
|||||||
@@ -1923,9 +1923,9 @@ onUnmounted(() => {
|
|||||||
:details="hidDetails"
|
:details="hidDetails"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- MSD Status - Admin only, hidden when CH9329 backend (no USB gadget support) -->
|
<!-- MSD Status - Hidden when CH9329 backend (no USB gadget support) -->
|
||||||
<StatusCard
|
<StatusCard
|
||||||
v-if="authStore.isAdmin && systemStore.msd?.available && systemStore.hid?.backend !== 'ch9329'"
|
v-if="systemStore.msd?.available && systemStore.hid?.backend !== 'ch9329'"
|
||||||
:title="t('statusCard.msd')"
|
:title="t('statusCard.msd')"
|
||||||
type="msd"
|
type="msd"
|
||||||
:status="msdStatus"
|
:status="msdStatus"
|
||||||
@@ -1988,7 +1988,6 @@ onUnmounted(() => {
|
|||||||
:mouse-mode="mouseMode"
|
:mouse-mode="mouseMode"
|
||||||
:video-mode="videoMode"
|
:video-mode="videoMode"
|
||||||
:ttyd-running="ttydStatus?.running"
|
:ttyd-running="ttydStatus?.running"
|
||||||
:is-admin="authStore.isAdmin"
|
|
||||||
@toggle-fullscreen="toggleFullscreen"
|
@toggle-fullscreen="toggleFullscreen"
|
||||||
@toggle-stats="statsSheetOpen = true"
|
@toggle-stats="statsSheetOpen = true"
|
||||||
@toggle-virtual-keyboard="handleToggleVirtualKeyboard"
|
@toggle-virtual-keyboard="handleToggleVirtualKeyboard"
|
||||||
|
|||||||
Reference in New Issue
Block a user