diff --git a/client/src/pages/api/plugins/file/delete.ts b/client/src/pages/api/plugins/file/delete.ts new file mode 100644 index 000000000..4b7a2f536 --- /dev/null +++ b/client/src/pages/api/plugins/file/delete.ts @@ -0,0 +1,30 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; +import { jsonRes } from '@/service/response'; +import { connectToDatabase } from '@/service/mongo'; +import { authUser } from '@/service/utils/auth'; +import { GridFSStorage } from '@/service/lib/gridfs'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + await connectToDatabase(); + + const { fileId } = req.query as { fileId: string }; + + if (!fileId) { + throw new Error('fileId is empty'); + } + + const { userId } = await authUser({ req }); + + const gridFs = new GridFSStorage('dataset', userId); + + await gridFs.delete(fileId); + + jsonRes(res); + } catch (error) { + jsonRes(res, { + code: 500, + error + }); + } +} diff --git a/client/src/pages/api/plugins/file/read.ts b/client/src/pages/api/plugins/file/read.ts index 9a7f0add8..b9572f368 100644 --- a/client/src/pages/api/plugins/file/read.ts +++ b/client/src/pages/api/plugins/file/read.ts @@ -1,20 +1,16 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { connectToDatabase } from '@/service/mongo'; -import { authUser } from '@/service/utils/auth'; import { GridFSStorage } from '@/service/lib/gridfs'; +import { authFileToken } from './readUrl'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { await connectToDatabase(); - const { fileId } = req.query as { fileId: string }; + const { token } = req.query as { token: string }; - if (!fileId) { - throw new Error('fileId is empty'); - } - - const { userId } = await authUser({ req }); + const { fileId, userId } = await authFileToken(token); const gridFs = new GridFSStorage('dataset', userId); @@ -25,6 +21,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< res.setHeader('encoding', file.encoding); res.setHeader('Content-Type', file.contentType); + res.setHeader('Cache-Control', 'public, max-age=3600'); res.end(buffer); } catch (error) { diff --git a/client/src/pages/api/plugins/file/readUrl.ts b/client/src/pages/api/plugins/file/readUrl.ts new file mode 100644 index 000000000..6b9cb51d9 --- /dev/null +++ b/client/src/pages/api/plugins/file/readUrl.ts @@ -0,0 +1,70 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; +import { jsonRes } from '@/service/response'; +import { connectToDatabase } from '@/service/mongo'; +import { authUser } from '@/service/utils/auth'; +import jwt from 'jsonwebtoken'; +import { ERROR_ENUM } from '@/service/errorCode'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + await connectToDatabase(); + + const { fileId } = req.query as { fileId: string }; + + if (!fileId) { + throw new Error('fileId is empty'); + } + + const { userId } = await authUser({ req }); + + const token = await createFileToken({ + userId, + fileId + }); + + jsonRes(res, { + data: `/api/plugins/file/read?token=${token}` + }); + } catch (error) { + jsonRes(res, { + code: 500, + error + }); + } +} + +export const createFileToken = (data: { userId: string; fileId: string }) => { + if (!process.env.FILE_TOKEN_KEY) { + return Promise.reject('System unset FILE_TOKEN_KEY'); + } + const expiredTime = Math.floor(Date.now() / 1000) + 60 * 30; + + const key = process.env.FILE_TOKEN_KEY as string; + const token = jwt.sign( + { + ...data, + exp: expiredTime + }, + key + ); + return Promise.resolve(token); +}; + +export const authFileToken = (token?: string) => + new Promise<{ userId: string; fileId: string }>((resolve, reject) => { + if (!token) { + return reject(ERROR_ENUM.unAuthFile); + } + const key = process.env.FILE_TOKEN_KEY as string; + + jwt.verify(token, key, function (err, decoded: any) { + if (err || !decoded?.userId || !decoded?.fileId) { + reject(ERROR_ENUM.unAuthFile); + return; + } + resolve({ + userId: decoded.userId, + fileId: decoded.fileId + }); + }); + });