feat: add user data directory permission repair functionality

This commit is contained in:
ezequielnick 2025-07-29 16:47:49 +08:00
parent 151726fcce
commit 827e744601
3 changed files with 92 additions and 6 deletions

View File

@ -151,4 +151,23 @@ else
fi fi
log "Installation completed successfully" log "Installation completed successfully"
# Fix user data directory permissions
log "Fixing user data directory permissions..."
for user_home in /Users/*; do
if [ -d "$user_home" ] && [ "$(basename "$user_home")" != "Shared" ] && [ "$(basename "$user_home")" != ".localized" ]; then
username=$(basename "$user_home")
user_data_dir="$user_home/Library/Application Support/mihomo-party"
if [ -d "$user_data_dir" ]; then
current_owner=$(stat -f "%Su" "$user_data_dir" 2>/dev/null || echo "unknown")
if [ "$current_owner" = "root" ]; then
log "Fixing ownership for user: $username"
chown -R "$username:staff" "$user_data_dir" 2>/dev/null || true
chmod -R u+rwX "$user_data_dir" 2>/dev/null || true
fi
fi
fi
done
exit 0 exit 0

View File

@ -10,8 +10,10 @@ import { createTray, hideDockIcon, showDockIcon } from './resolve/tray'
import { init } from './utils/init' import { init } from './utils/init'
import { join } from 'path' import { join } from 'path'
import { initShortcut } from './resolve/shortcut' import { initShortcut } from './resolve/shortcut'
import { execSync, spawn } from 'child_process' import { execSync, spawn, exec } from 'child_process'
import { createElevateTask } from './sys/misc' import { createElevateTask } from './sys/misc'
import { promisify } from 'util'
import { stat } from 'fs/promises'
import { initProfileUpdater } from './core/profileUpdater' import { initProfileUpdater } from './core/profileUpdater'
import { existsSync, writeFileSync } from 'fs' import { existsSync, writeFileSync } from 'fs'
import { exePath, taskDir } from './utils/dirs' import { exePath, taskDir } from './utils/dirs'
@ -22,6 +24,29 @@ import iconv from 'iconv-lite'
import { initI18n } from '../shared/i18n' import { initI18n } from '../shared/i18n'
import i18next from 'i18next' import i18next from 'i18next'
async function fixUserDataPermissions(): Promise<void> {
if (process.platform !== 'darwin') return
const userDataPath = app.getPath('userData')
if (!existsSync(userDataPath)) return
try {
const stats = await stat(userDataPath)
const currentUid = process.getuid?.() || 0
if (stats.uid === 0 && currentUid !== 0) {
const execPromise = promisify(exec)
const username = process.env.USER || process.env.LOGNAME
if (username) {
await execPromise(`chown -R "${username}:staff" "${userDataPath}"`)
await execPromise(`chmod -R u+rwX "${userDataPath}"`)
}
}
} catch {
// ignore
}
}
let quitTimeout: NodeJS.Timeout | null = null let quitTimeout: NodeJS.Timeout | null = null
export let mainWindow: BrowserWindow | null = null export let mainWindow: BrowserWindow | null = null
@ -59,12 +84,27 @@ if (process.platform === 'win32' && !is.dev && !process.argv.includes('noadmin')
} }
} }
const gotTheLock = app.requestSingleInstanceLock() async function initApp(): Promise<void> {
await fixUserDataPermissions()
if (!gotTheLock) {
app.quit()
} }
initApp()
.then(() => {
const gotTheLock = app.requestSingleInstanceLock()
if (!gotTheLock) {
app.quit()
}
})
.catch(() => {
// ignore permission fix errors
const gotTheLock = app.requestSingleInstanceLock()
if (!gotTheLock) {
app.quit()
}
})
export function customRelaunch(): void { export function customRelaunch(): void {
const script = `while kill -0 ${process.pid} 2>/dev/null; do const script = `while kill -0 ${process.pid} 2>/dev/null; do
sleep 0.1 sleep 0.1

View File

@ -22,8 +22,10 @@ import {
defaultProfileConfig defaultProfileConfig
} from './template' } from './template'
import yaml from 'yaml' import yaml from 'yaml'
import { mkdir, writeFile,rm, readdir, cp } from 'fs/promises' import { mkdir, writeFile, rm, readdir, cp, stat } from 'fs/promises'
import { existsSync } from 'fs' import { existsSync } from 'fs'
import { exec } from 'child_process'
import { promisify } from 'util'
import path from 'path' import path from 'path'
import { import {
startPacServer, startPacServer,
@ -40,7 +42,32 @@ import {
import { app } from 'electron' import { app } from 'electron'
import { startSSIDCheck } from '../sys/ssid' import { startSSIDCheck } from '../sys/ssid'
async function fixDataDirPermissions(): Promise<void> {
if (process.platform !== 'darwin') return
const dataDirPath = dataDir()
if (!existsSync(dataDirPath)) return
try {
const stats = await stat(dataDirPath)
const currentUid = process.getuid?.() || 0
if (stats.uid === 0 && currentUid !== 0) {
const execPromise = promisify(exec)
const username = process.env.USER || process.env.LOGNAME
if (username) {
await execPromise(`chown -R "${username}:staff" "${dataDirPath}"`)
await execPromise(`chmod -R u+rwX "${dataDirPath}"`)
}
}
} catch {
// ignore
}
}
async function initDirs(): Promise<void> { async function initDirs(): Promise<void> {
await fixDataDirPermissions()
if (!existsSync(dataDir())) { if (!existsSync(dataDir())) {
await mkdir(dataDir()) await mkdir(dataDir())
} }