onedrive/pages/api/raw.ts

82 lines
2.7 KiB
TypeScript

import { posix as pathPosix } from 'path'
import type { NextApiRequest, NextApiResponse } from 'next'
import axios from 'axios'
import Cors from 'cors'
import { driveApi } 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 = '' } = 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,@microsoft.graph.downloadUrl',
},
})
if ('@microsoft.graph.downloadUrl' in data) {
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
}
}