onedrive/pages/api/thumbnail.ts
2022-02-10 23:06:11 +08:00

69 lines
2.4 KiB
TypeScript

import type { OdThumbnail } from '../../types'
import { posix as pathPosix } from 'path'
import axios from 'axios'
import type { NextApiRequest, NextApiResponse } from 'next'
import { encodePath, getAccessToken, getAuthTokenPath } from '.'
import apiConfig from '../../config/api.config'
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
// Get access token from storage
const accessToken = await getAccessToken()
// Get item thumbnails by its path since we will later check if it is protected
const { path = '', size = 'medium' } = req.query
// Set edge function caching for faster load times, check docs:
// https://vercel.com/docs/concepts/functions/edge-caching
res.setHeader('Cache-Control', 'max-age=0, s-maxage=600, stale-while-revalidate')
// Check whether the size is valid - must be one of 'large', 'medium', or 'small'
if (size !== 'large' && size !== 'medium' && size !== 'small') {
res.status(400).json({ error: 'Invalid size' })
return
}
// 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))
// Check if the path is protected
const authTokenPath = getAuthTokenPath(cleanPath)
// Currently protected paths are rejected to avoid file content leak
if (authTokenPath) {
res.status(404).json({ error: 'Protected pathes are not allowed.' })
return
}
const requestPath = encodePath(cleanPath)
// Handle response from OneDrive API
const requestUrl = `${apiConfig.driveApi}/root${requestPath}`
// Whether path is root, which requires some special treatment
const isRoot = requestPath === ''
try {
const { data } = await axios.get(`${requestUrl}${isRoot ? '' : ':'}/thumbnails`, {
headers: { Authorization: `Bearer ${accessToken}` },
})
const thumbnailUrl = data.value && data.value.length > 0 ? (data.value[0] as OdThumbnail)[size].url : null
if (thumbnailUrl) {
res.redirect(thumbnailUrl)
} else {
res.status(400).json({ error: "The item doesn't have a valid thumbnail." })
}
} catch (error: any) {
res.status(error.response.status).json({ error: error.response.data })
}
return
}