Skip to content

Commit

Permalink
fix: password protected non-media files (#496)
Browse files Browse the repository at this point in the history
  • Loading branch information
diced committed Nov 22, 2023
1 parent e5ac971 commit 6ef3c82
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 16 deletions.
24 changes: 17 additions & 7 deletions src/pages/view/[id].tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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);

Expand All @@ -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();
Expand Down Expand Up @@ -163,14 +171,13 @@ export default function EmbeddedFile({
<Modal
opened={opened}
onClose={() => setOpened(false)}
title='Password Protected'
title={<Title order={3}>Password Protected</Title>}
centered={true}
withCloseButton={true}
withCloseButton={false}
closeOnEscape={false}
closeOnClickOutside={false}
>
<PasswordInput
label='Password'
placeholder='Password'
error={error}
value={password}
Expand Down Expand Up @@ -203,7 +210,7 @@ export default function EmbeddedFile({
{!file.mimetype.startsWith('video') &&
!file.mimetype.startsWith('image') &&
!file.mimetype.startsWith('audio') && (
<AnchorNext component={Link} href={dataURL('/r')}>
<AnchorNext component={Link} href={dataURL('/r', downloadWPass ? password : undefined)}>
Can&#39;t preview this file. Click here to download it.
</AnchorNext>
)}
Expand All @@ -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 (
Expand Down
26 changes: 17 additions & 9 deletions src/server/routes/raw.ts
Original file line number Diff line number Diff line change
@@ -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({
Expand All @@ -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);
}
}

0 comments on commit 6ef3c82

Please sign in to comment.