Fix 403 error when loading music files
- Fix path traversal security check by using absolute paths - Remove problematic fetch override that forced JSON headers on all API requests - Add error tracking and visual indicators for failed tracks - Correct music directory resolution for both relative and absolute paths The main issue was the security validation comparing relative paths incorrectly, causing legitimate music file requests to be rejected with 403 errors.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { promises as fs } from 'fs'
|
||||
import { join } from 'path'
|
||||
import { join, resolve, sep } from 'path'
|
||||
import { createReadStream } from 'fs'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
@@ -12,17 +12,14 @@ export default defineEventHandler(async (event) => {
|
||||
})
|
||||
}
|
||||
|
||||
// Log incoming request for debugging proxy issues
|
||||
// Log incoming request
|
||||
const headers = getHeaders(event)
|
||||
const realIP = headers['x-real-ip'] || headers['x-forwarded-for'] || 'unknown'
|
||||
console.log(`[MUSIC API] Request from ${realIP} for file: ${filename}`)
|
||||
console.log('Original filename bytes:', [...filename].map(c => c.charCodeAt(0)))
|
||||
|
||||
// Decode the filename
|
||||
try {
|
||||
filename = decodeURIComponent(filename)
|
||||
console.log('Decoded filename:', filename)
|
||||
console.log('Decoded filename bytes:', [...filename].map(c => c.charCodeAt(0)))
|
||||
} catch (error) {
|
||||
console.error('Error decoding filename:', error)
|
||||
// If decoding fails, use original filename
|
||||
@@ -30,13 +27,27 @@ export default defineEventHandler(async (event) => {
|
||||
|
||||
try {
|
||||
const config = useRuntimeConfig()
|
||||
const defaultPublicPath = config.public?.musicPath || '/music'
|
||||
const publicRel = defaultPublicPath.replace(/^\//, '')
|
||||
const musicDir = process.env.MUSIC_DIR || join(process.cwd(), 'public', publicRel)
|
||||
const filePath = join(musicDir, filename)
|
||||
|
||||
// Determine the music directory path
|
||||
let musicDir: string
|
||||
if (process.env.MUSIC_DIR) {
|
||||
// If MUSIC_DIR is set, resolve it (handles both absolute and relative paths)
|
||||
musicDir = resolve(process.cwd(), process.env.MUSIC_DIR)
|
||||
} else {
|
||||
// Fallback to public/music
|
||||
const defaultPublicPath = config.public?.musicPath || '/music'
|
||||
const publicRel = defaultPublicPath.replace(/^\//, '')
|
||||
musicDir = resolve(process.cwd(), 'public', publicRel)
|
||||
}
|
||||
|
||||
// Resolve the full file path
|
||||
const filePath = resolve(musicDir, filename)
|
||||
|
||||
// Security check: ensure the file is within the music directory
|
||||
if (!filePath.startsWith(musicDir)) {
|
||||
// Normalize both paths and add separator to ensure exact directory match
|
||||
const normalizedMusicDir = musicDir.endsWith(sep) ? musicDir : musicDir + sep
|
||||
|
||||
if (!filePath.startsWith(normalizedMusicDir)) {
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: 'Access denied'
|
||||
@@ -46,16 +57,7 @@ export default defineEventHandler(async (event) => {
|
||||
// Check if file exists
|
||||
try {
|
||||
await fs.access(filePath)
|
||||
console.log('File found successfully:', filePath)
|
||||
} catch (error) {
|
||||
console.log('File NOT found:', filePath)
|
||||
console.log('Directory contents:')
|
||||
try {
|
||||
const files = await fs.readdir(musicDir)
|
||||
files.forEach(file => console.log(' -', file))
|
||||
} catch (e) {
|
||||
console.log('Cannot read directory:', e)
|
||||
}
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: 'File not found'
|
||||
|
||||
Reference in New Issue
Block a user