mirror of
https://github.com/Nezumi-2711/onedrive-vercel-index.git
synced 2026-09-22 20:01:46 +00:00
94 lines
3.2 KiB
TypeScript
94 lines
3.2 KiB
TypeScript
import { posix as pathPosix } from 'path'
|
|
|
|
import type { NextApiRequest, NextApiResponse } from 'next'
|
|
import axios from 'axios'
|
|
import Cors from 'cors'
|
|
|
|
import { driveApi, cacheControlHeader } from '../../config/api.config'
|
|
import { encodePath, getAccessToken, checkAuthRoute } from '.'
|
|
|
|
// CORS middleware for raw links: https://nextjs.org/docs/api-routes/api-middlewares
|
|
export function runCorsMiddleware(req: NextApiRequest, res: NextApiResponse) {
|
|
const cors = Cors({ methods: ['GET', 'HEAD'] })
|
|
return new Promise((resolve, reject) => {
|
|
cors(req, res, result => {
|
|
if (result instanceof Error) {
|
|
return reject(result)
|
|
}
|
|
|
|
return resolve(result)
|
|
})
|
|
})
|
|
}
|
|
|
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
const accessToken = await getAccessToken()
|
|
if (!accessToken) {
|
|
res.status(403).json({ error: 'No access token.' })
|
|
return
|
|
}
|
|
|
|
const { path = '/', odpt = '', proxy = false } = req.query
|
|
|
|
// Sometimes the path parameter is defaulted to '[...path]' which we need to handle
|
|
if (path === '[...path]') {
|
|
res.status(400).json({ error: 'No path specified.' })
|
|
return
|
|
}
|
|
// If the path is not a valid path, return 400
|
|
if (typeof path !== 'string') {
|
|
res.status(400).json({ error: 'Path query invalid.' })
|
|
return
|
|
}
|
|
const cleanPath = pathPosix.resolve('/', pathPosix.normalize(path))
|
|
|
|
// Handle protected routes authentication
|
|
const odTokenHeader = (req.headers['od-protected-token'] as string) ?? odpt
|
|
|
|
const { code, message } = await checkAuthRoute(cleanPath, accessToken, odTokenHeader)
|
|
// Status code other than 200 means user has not authenticated yet
|
|
if (code !== 200) {
|
|
res.status(code).json({ error: message })
|
|
return
|
|
}
|
|
// If message is empty, then the path is not protected.
|
|
// Conversely, protected routes are not allowed to serve from cache.
|
|
if (message !== '') {
|
|
res.setHeader('Cache-Control', 'no-cache')
|
|
}
|
|
|
|
await runCorsMiddleware(req, res)
|
|
try {
|
|
// Handle response from OneDrive API
|
|
const requestUrl = `${driveApi}/root${encodePath(cleanPath)}`
|
|
const { data } = await axios.get(requestUrl, {
|
|
headers: { Authorization: `Bearer ${accessToken}` },
|
|
params: {
|
|
// OneDrive international version fails when only selecting the downloadUrl (what a stupid bug)
|
|
select: 'id,size,@microsoft.graph.downloadUrl',
|
|
},
|
|
})
|
|
|
|
if ('@microsoft.graph.downloadUrl' in data) {
|
|
// Only proxy raw file content response for files up to 4MB
|
|
if (proxy && 'size' in data && data['size'] < 4194304) {
|
|
const { headers, data: stream } = await axios.get(data['@microsoft.graph.downloadUrl'] as string, {
|
|
responseType: 'stream',
|
|
})
|
|
headers['Cache-Control'] = cacheControlHeader
|
|
// Send data stream as response
|
|
res.writeHead(200, headers)
|
|
stream.pipe(res)
|
|
} else {
|
|
res.redirect(data['@microsoft.graph.downloadUrl'])
|
|
}
|
|
} else {
|
|
res.status(404).json({ error: 'No download url found.' })
|
|
}
|
|
return
|
|
} catch (error: any) {
|
|
res.status(error?.response?.status ?? 500).json({ error: error?.response?.data ?? 'Internal server error.' })
|
|
return
|
|
}
|
|
}
|