diff --git a/src/main/core/manager.ts b/src/main/core/manager.ts index 81a36ec..4e2c928 100644 --- a/src/main/core/manager.ts +++ b/src/main/core/manager.ts @@ -19,7 +19,7 @@ let retry = 10 export async function startCore(): Promise { const { core = 'mihomo' } = await getAppConfig() const corePath = mihomoCorePath(core) - await grantCorePermition(corePath) + await autoGrantCorePermition(corePath) await generateProfile() await checkProfile() stopCore() @@ -90,7 +90,7 @@ async function checkProfile(): Promise { } } -export async function grantCorePermition(corePath: string): Promise { +export async function autoGrantCorePermition(corePath: string): Promise { const { encryptedPassword } = await getAppConfig() const execPromise = promisify(exec) if (encryptedPassword && isEncryptionAvailable()) { @@ -117,6 +117,17 @@ export async function grantCorePermition(corePath: string): Promise { } } +export async function manualGrantCorePermition(): Promise { + const { core = 'mihomo' } = await getAppConfig() + const corePath = mihomoCorePath(core) + const execPromise = promisify(exec) + if (process.platform === 'darwin') { + const shell = `chown root:admin ${corePath}\nchmod +sx ${corePath}` + const command = `do shell script "${shell}" with administrator privileges` + await execPromise(`osascript -e '${command}'`) + } +} + export function isEncryptionAvailable(): boolean { return safeStorage.isEncryptionAvailable() } diff --git a/src/main/utils/ipc.ts b/src/main/utils/ipc.ts index a26b954..dd14ebd 100644 --- a/src/main/utils/ipc.ts +++ b/src/main/utils/ipc.ts @@ -44,7 +44,7 @@ import { setOverride, updateOverrideItem } from '../config' -import { isEncryptionAvailable, restartCore } from '../core/manager' +import { isEncryptionAvailable, manualGrantCorePermition, restartCore } from '../core/manager' import { triggerSysProxy } from '../resolve/sysproxy' import { checkUpdate } from '../resolve/autoUpdater' import { exePath, mihomoCorePath, mihomoWorkConfigPath, resourcesDir } from './dirs' @@ -128,6 +128,7 @@ export function registerIpcMainHandlers(): void { ipcMain.handle('triggerSysProxy', (_e, enable) => ipcErrorWrapper(triggerSysProxy)(enable)) ipcMain.handle('isEncryptionAvailable', isEncryptionAvailable) ipcMain.handle('encryptString', (_e, str) => safeStorage.encryptString(str)) + ipcMain.handle('manualGrantCorePermition', ipcErrorWrapper(manualGrantCorePermition)) ipcMain.handle('getFilePath', (_e, ext) => getFilePath(ext)) ipcMain.handle('readTextFile', (_e, filePath) => ipcErrorWrapper(readTextFile)(filePath)) ipcMain.handle('getRuntimeConfigStr', ipcErrorWrapper(getRuntimeConfigStr)) diff --git a/src/renderer/src/pages/tun.tsx b/src/renderer/src/pages/tun.tsx index 3130559..68fc373 100644 --- a/src/renderer/src/pages/tun.tsx +++ b/src/renderer/src/pages/tun.tsx @@ -3,7 +3,7 @@ import BasePage from '@renderer/components/base/base-page' import SettingCard from '@renderer/components/base/base-setting-card' import SettingItem from '@renderer/components/base/base-setting-item' import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config' -import { restartCore, setupFirewall } from '@renderer/utils/ipc' +import { manualGrantCorePermition, restartCore, setupFirewall } from '@renderer/utils/ipc' import { platform } from '@renderer/utils/init' import React, { Key, useState } from 'react' @@ -88,6 +88,29 @@ const Tun: React.FC = () => { )} + {platform === 'darwin' && ( + + + + )} { return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('encryptString', str)) } +export async function manualGrantCorePermition(): Promise { + return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('manualGrantCorePermition')) +} + export async function getFilePath(ext: string[]): Promise { return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('getFilePath', ext)) }