fix(service): explain core security failures and link repair guidance

This commit is contained in:
wonfen
2026-09-24 18:43:27 +08:00
parent fbc4b516b8
commit ae4f416766
21 changed files with 105 additions and 14 deletions
+42
View File
@@ -3,6 +3,7 @@ import {
Snackbar,
Alert,
IconButton,
Link,
Box,
Stack,
type SnackbarOrigin,
@@ -18,6 +19,12 @@ import {
showNotice,
} from '@/services/notice-service'
import type { TranslationKey } from '@/types/generated/i18n-keys'
import { openExternalUrl } from '@/utils/open-external-url'
const SERVICE_PERMISSION_NOTICE =
'settings.feedback.notifications.clashService.permissionFallback'
const SERVICE_PERMISSION_GUIDE =
'https://clash-verge-rev.github.io/faq/windows.html#service-core-permissions'
type NoticePosition = NonNullable<IVergeConfig['notice_position']>
type NoticeItem = ReturnType<typeof getSnapshotNotices>[number]
@@ -59,6 +66,38 @@ const resolveNoticeMessage = (
const i18n = notice.i18n
if (!i18n) return bound(notice.message)
if (i18n.key === SERVICE_PERMISSION_NOTICE) {
const reason = i18n.params?.reason
return (
<>
{t(SERVICE_PERMISSION_NOTICE, {
reason: t(
typeof reason === 'string' && reason.includes('is writable by')
? 'settings.feedback.notifications.clashService.permissionWritableReason'
: 'settings.feedback.notifications.clashService.permissionRejectedReason',
),
})}
<Box sx={{ mt: 1 }}>
<Link
href={SERVICE_PERMISSION_GUIDE}
color="inherit"
underline="always"
onClick={(event) => {
event.preventDefault()
void openExternalUrl(SERVICE_PERMISSION_GUIDE).catch(
showNotice.error,
)
}}
>
{t(
'settings.feedback.notifications.clashService.permissionRepairGuide',
)}
</Link>
</Box>
</>
)
}
const source = (i18n.params ?? {}) as Record<string, unknown>
// Bound both parameters and their final interpolation.
const params =
@@ -132,6 +171,9 @@ const resolveNoticeCopyText = (
notice: NoticeItem,
t: TranslationFn,
): string | undefined => {
if (notice.i18n?.key === SERVICE_PERMISSION_NOTICE) {
return extractNoticeCopyText(notice.i18n.params?.reason)
}
if (
notice.i18n?.key === 'shared.feedback.notices.prefixedRaw' ||
notice.i18n?.key === 'shared.feedback.notices.raw'
@@ -78,6 +78,7 @@ it('reports the permission refusal and finishes after installation falls back to
expect(showNotice.warning).toHaveBeenCalledWith(
'settings.feedback.notifications.clashService.permissionFallback',
{ reason },
0,
)
})
@@ -116,6 +116,7 @@ export const ServiceMigrationDialog = () => {
showNotice.warning(
'settings.feedback.notifications.clashService.permissionFallback',
{ reason: outcome.reason },
0,
)
return
}
@@ -112,6 +112,7 @@ export const SysproxyPrivilegeDialog = () => {
showNotice.warning(
'settings.feedback.notifications.clashService.permissionFallback',
{ reason: outcome.reason },
0,
)
close()
return