Skip to content

Commit

Permalink
[FIX] Add permission checks and timeout handling to copyRecursiveAsyn…
Browse files Browse the repository at this point in the history
…c function
  • Loading branch information
flavioislima committed Dec 10, 2024
1 parent 6bc755d commit f635bbe
Showing 1 changed file with 48 additions and 3 deletions.
51 changes: 48 additions & 3 deletions src/backend/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ import {
deviceNameCache,
vendorNameCache
} from './utils/systeminfo/gpu/pci_ids'
import { copyFile, lstat, mkdir, readdir } from 'fs/promises'
import { access, constants, copyFile, lstat, mkdir, readdir } from 'fs/promises'
import { GameConfig } from './game_config'

const execAsync = promisify(exec)
Expand Down Expand Up @@ -1306,31 +1306,76 @@ export const writeConfig = (appName: string, config: Partial<AppSettings>) => {
}
}

// Helper function to check permissions
async function checkPermissions(src: string, dest: string) {
try {
// Check if we can read from source
await access(src, constants.R_OK)

// Check if destination parent directory exists and is writable
const destDir = dirname(dest)
try {
await access(destDir, constants.W_OK)
} catch {
throw new Error(
`No write permission for destination directory: ${destDir}`
)
}
} catch (error) {
if (error instanceof Error) {
throw new Error(`Permission error: ${error.message}`)
}
throw error
}
}

const COPY_TIMEOUT_MS = 30000 // wait time before throwing a timeout error
export async function copyRecursiveAsync(src: string, dest: string) {
if (!existsSync(src) || !src || !dest) {
return
}

// Check permissions before proceeding
await checkPermissions(src, dest)

const stats = await lstat(src)
if (stats.isSymbolicLink()) {
return // Skip symbolic links
}

if (stats.isDirectory()) {
try {
await mkdir(dest, { recursive: true })
const files = await readdir(src)
for (const file of files) {
const srcFile = join(src, file)
const destFile = join(dest, file)
await copyRecursiveAsync(srcFile, destFile)
await Promise.race([
copyRecursiveAsync(srcFile, destFile),
wait(COPY_TIMEOUT_MS).then(() => {
throw new Error(
`Timeout (${COPY_TIMEOUT_MS}ms) copying ${srcFile} to ${destFile}`
)
})
])
}
} catch (error) {
logError(`Failed to copy ${src} to ${dest}: ${error}`, LogPrefix.Backend)
throw error
}
} else {
try {
await copyFile(src, dest)
await Promise.race([
copyFile(src, dest),
wait(COPY_TIMEOUT_MS).then(() => {
throw new Error(
`Timeout (${COPY_TIMEOUT_MS}ms) copying ${src} to ${dest}`
)
})
])
} catch (error) {
logError(`Failed to copy ${src} to ${dest}: ${error}`, LogPrefix.Backend)
throw error
}
}
}

0 comments on commit f635bbe

Please sign in to comment.