diff --git a/src/pages/view/[id].tsx b/src/pages/view/[id].tsx index 52805127f..1161b6abb 100644 --- a/src/pages/view/[id].tsx +++ b/src/pages/view/[id].tsx @@ -1,4 +1,4 @@ -import { Box, Button, Modal, PasswordInput } from '@mantine/core'; +import { Box, Button, Modal, PasswordInput, Title } from '@mantine/core'; import type { File, Thumbnail } from '@prisma/client'; import AnchorNext from 'components/AnchorNext'; import exts from 'lib/exts'; @@ -27,13 +27,18 @@ export default function EmbeddedFile({ host: string; compress?: boolean; }) { - const dataURL = (route: string) => `${route}/${encodeURI(file.name)}?compress=${compress ?? false}`; + const dataURL = (route: string, pass?: string) => + `${route}/${encodeURIComponent(file.name)}?compress=${compress ?? false}${ + pass ? `&password=${encodeURIComponent(pass)}` : '' + }`; const router = useRouter(); - const [opened, setOpened] = useState(pass); + const [opened, setOpened] = useState(pass || !!file.password); const [password, setPassword] = useState(''); const [error, setError] = useState(''); + const [downloadWPass, setDownloadWPass] = useState(false); + // reapply date from workaround file.createdAt = new Date(file ? file.createdAt : 0); @@ -45,12 +50,15 @@ export default function EmbeddedFile({ if (prismRender) return router.push(`/code/${file.name}?password=${password}`); updateImage(`/api/auth/image?id=${file.id}&password=${password}`); setOpened(false); + setDownloadWPass(true); } else { setError('Invalid password'); } }; const updateImage = async (url?: string) => { + if (!file.mimetype.startsWith('image')) return; + const imageEl = document.getElementById('image_content') as HTMLImageElement; const img = new Image(); @@ -163,14 +171,13 @@ export default function EmbeddedFile({ setOpened(false)} - title='Password Protected' + title={Password Protected} centered={true} - withCloseButton={true} + withCloseButton={false} closeOnEscape={false} closeOnClickOutside={false} > + Can't preview this file. Click here to download it. )} @@ -226,6 +233,9 @@ export const getServerSideProps: GetServerSideProps = async (context) => { let host = context.req.headers.host; if (!file) return { notFound: true }; + // @ts-ignore + file.size = Number(file.size); + const proto = context.req.headers['x-forwarded-proto']; try { if ( diff --git a/src/server/routes/raw.ts b/src/server/routes/raw.ts index 1419654c4..59a643b13 100644 --- a/src/server/routes/raw.ts +++ b/src/server/routes/raw.ts @@ -1,7 +1,9 @@ import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'; +import { checkPassword } from 'lib/util'; export default async function rawRoute(this: FastifyInstance, req: FastifyRequest, reply: FastifyReply) { const { id } = req.params as { id: string }; + const { password } = req.query as { password: string }; if (id === '') return reply.notFound(); const file = await this.prisma.file.findFirst({ @@ -16,14 +18,20 @@ export default async function rawRoute(this: FastifyInstance, req: FastifyReques if (failed) return reply.notFound(); if (file.password) { - return reply - .type('application/json') - .code(403) - .send({ - error: "can't view a raw file that has a password", - url: `/view/${file.name}`, - code: 403, - }); - } else return reply.rawFile(file.name); + if (!password) + return reply + .type('application/json') + .code(403) + .send({ error: 'password protected', url: `/view/${file.name}`, code: 403 }); + const success = await checkPassword(password, file.password); + + if (!success) + return reply + .type('application/json') + .code(403) + .send({ error: 'incorrect password', url: `/view/${file.name}`, code: 403 }); + } + + return reply.rawFile(file.name); } }