1
Fork 0
mirror of https://github.com/diced/zipline.git synced 2025-04-11 23:31:17 -05:00

fix: at least check the password before anything else >:(

and no more rawdogging it if the db doesn't have it!
This commit is contained in:
Jayvin Hernandez 2025-02-06 17:53:11 -08:00
parent 9edb38fedc
commit 7ef20827fb
No known key found for this signature in database
GPG key ID: 97C2E533F17AF0EB
6 changed files with 51 additions and 148 deletions

View file

@ -1,98 +0,0 @@
import { File } from '@prisma/client';
import { FastifyInstance, FastifyReply } from 'fastify';
import fastifyPlugin from 'fastify-plugin';
import exts from 'lib/exts';
import { parseRange } from 'lib/utils/range';
function dbFileDecorator(fastify: FastifyInstance, _, done) {
fastify.decorateReply('dbFile', dbFile);
done();
async function dbFile(this: FastifyReply, file: File) {
const { download } = this.request.query as { download?: string };
const ext = file.name.split('.').pop();
if (Object.keys(exts).includes(ext)) return this.server.nextHandle(this.request.raw, this.raw);
const size = await this.server.datasource.size(file.name);
if (size === null) return this.notFound();
if (this.request.headers.range) {
const [start, end] = parseRange(this.request.headers.range, size);
if (start >= size || end >= size) {
const buf = await datasource.get(file.name);
if (!buf) return this.server.nextServer.render404(this.request.raw, this.raw);
return this.type(file.mimetype || 'application/octet-stream')
.headers({
'Content-Length': size,
...(file.originalName
? {
'Content-Disposition': `${download ? 'attachment; ' : ''}filename="${encodeURIComponent(
file.originalName,
)}"`,
}
: download && {
'Content-Disposition': 'attachment;',
}),
})
.status(416)
.send(buf);
}
const buf = await datasource.range(file.name, start || 0, end);
if (!buf) return this.server.nextServer.render404(this.request.raw, this.raw);
return this.type(file.mimetype || 'application/octet-stream')
.headers({
'Content-Range': `bytes ${start}-${end}/${size}`,
'Accept-Ranges': 'bytes',
'Content-Length': end - start + 1,
...(file.originalName
? {
'Content-Disposition': `${download ? 'attachment; ' : ''}filename="${encodeURIComponent(
file.originalName,
)}"`,
}
: download && {
'Content-Disposition': 'attachment;',
}),
})
.status(206)
.send(buf);
}
const data = await datasource.get(file.name);
if (!data) return this.server.nextServer.render404(this.request.raw, this.raw);
return this.type(file.mimetype || 'application/octet-stream')
.headers({
'Content-Length': size,
'Accept-Ranges': 'bytes',
...(file.originalName
? {
'Content-Disposition': `${download ? 'attachment; ' : ''}filename="${encodeURIComponent(
file.originalName,
)}"`,
}
: download && {
'Content-Disposition': 'attachment;',
}),
})
.status(200)
.send(data);
}
}
export default fastifyPlugin(dbFileDecorator, {
name: 'dbFile',
decorators: {
fastify: ['prisma', 'datasource', 'nextHandle', 'logger'],
},
});
declare module 'fastify' {
interface FastifyReply {
dbFile: (file: File) => Promise<void>;
}
}

View file

@ -30,6 +30,6 @@ export default fastifyPlugin(preFileDecorator, {
declare module 'fastify' {
interface FastifyReply {
preFile: (file: File) => Promise<boolean>;
preFile: (file: Partial<File>) => Promise<boolean>;
}
}

View file

@ -6,52 +6,53 @@ import { createBrotliCompress, createDeflate, createGzip } from 'zlib';
import pump from 'pump';
import { Transform } from 'stream';
import { parseRange } from 'lib/utils/range';
import { File } from '@prisma/client';
function rawFileDecorator(fastify: FastifyInstance, _, done) {
fastify.decorateReply('rawFile', rawFile);
done();
async function rawFile(this: FastifyReply, id: string) {
async function rawFile(this: FastifyReply, file: Partial<File>) {
const { download, compress = 'false' } = this.request.query as { download?: string; compress?: string };
const size = await this.server.datasource.size(id);
const size = await this.server.datasource.size(file.name);
if (size === null) return this.notFound();
const mimetype = await guess(extname(id).slice(1));
const mimetype = await guess(extname(file.name).slice(1));
if (this.request.headers.range) {
const [start, end] = parseRange(this.request.headers.range, size);
if (start >= size || end >= size) {
const buf = await datasource.get(id);
const buf = await datasource.get(file.name);
if (!buf) return this.server.nextServer.render404(this.request.raw, this.raw);
return this.type(mimetype || 'application/octet-stream')
return this.type(file.mimetype || mimetype || 'application/octet-stream')
.headers({
'Content-Length': size,
...(download && {
'Content-Disposition': 'attachment;',
}),
'Content-Disposition': `${download ? 'attachment; ' : ''}filename="${encodeURIComponent(
file.originalName ?? file.name,
)}`,
})
.status(416)
.send(buf);
}
const buf = await datasource.range(id, start || 0, end);
const buf = await datasource.range(file.name, start || 0, end);
if (!buf) return this.server.nextServer.render404(this.request.raw, this.raw);
return this.type(mimetype || 'application/octet-stream')
return this.type(file.mimetype || mimetype || 'application/octet-stream')
.headers({
'Content-Range': `bytes ${start}-${end}/${size}`,
'Accept-Ranges': 'bytes',
'Content-Length': end - start + 1,
...(download && {
'Content-Disposition': 'attachment;',
}),
'Content-Disposition': `${download ? 'attachment; ' : ''}filename="${encodeURIComponent(
file.originalName ?? file.name,
)}`,
})
.status(206)
.send(buf);
}
const data = await datasource.get(id);
const data = await datasource.get(file.name);
if (!data) return this.server.nextServer.render404(this.request.raw, this.raw);
if (
@ -61,7 +62,7 @@ function rawFileDecorator(fastify: FastifyInstance, _, done) {
)
if (
size > this.server.config.core.compression.threshold &&
mimetype.match(/^(image(?!\/(webp))|video(?!\/(webm))|text)/)
(file.mimetype || mimetype).match(/^(image(?!\/(webp))|vfileeo(?!\/(webm))|text)/)
)
return this.send(useCompress.call(this, data));
@ -69,9 +70,9 @@ function rawFileDecorator(fastify: FastifyInstance, _, done) {
.headers({
'Content-Length': size,
'Accept-Ranges': 'bytes',
...(download && {
'Content-Disposition': 'attachment;',
}),
'Content-Disposition': `${download ? 'attachment; ' : ''}filename="${encodeURIComponent(
file.originalName ?? file.name,
)}`,
})
.status(200)
.send(data);
@ -115,6 +116,6 @@ export default fastifyPlugin(rawFileDecorator, {
declare module 'fastify' {
interface FastifyReply {
rawFile: (id: string) => Promise<void>;
rawFile: (file: Partial<File>) => Promise<void>;
}
}

View file

@ -7,7 +7,6 @@ import { version } from '../../package.json';
import fastify, { FastifyInstance, FastifyServerOptions } from 'fastify';
import { createReadStream, existsSync, readFileSync } from 'fs';
import { Worker } from 'worker_threads';
import dbFileDecorator from './decorators/dbFile';
import notFound from './decorators/notFound';
import postFileDecorator from './decorators/postFile';
import postUrlDecorator from './decorators/postUrl';
@ -66,8 +65,7 @@ async function start() {
.register(postUrlDecorator)
.register(postFileDecorator)
.register(preFileDecorator)
.register(rawFileDecorator)
.register(dbFileDecorator);
.register(rawFileDecorator);
server.addHook('onRequest', (req, reply, done) => {
if (config.features.headless) {

View file

@ -10,28 +10,34 @@ export default async function rawRoute(this: FastifyInstance, req: FastifyReques
where: {
OR: [{ name: id }, { invisible: { invis: decodeURI(encodeURI(id)) } }],
},
select: {
name: true,
originalName: true,
mimetype: true,
password: true,
favorite: true,
expiresAt: true,
},
});
if (!file) return reply.rawFile(id);
else {
const failed = await reply.preFile(file);
if (failed) return reply.notFound();
if (!file) return reply.notFound();
if (file.password) {
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 (file.password) {
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);
if (!success)
return reply
.type('application/json')
.code(403)
.send({ error: 'incorrect password', url: `/view/${file.name}`, code: 403 });
}
if (await reply.preFile(file)) return reply.notFound();
return reply.rawFile(file);
}

View file

@ -1,10 +1,9 @@
import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
import exts from 'lib/exts';
export default async function uploadsRoute(this: FastifyInstance, req: FastifyRequest, reply: FastifyReply) {
const { id } = req.params as { id: string };
if (id === '') return reply.notFound();
else if (id === 'dashboard' && !this.config.features.headless)
else if (id === 'dashboard' && !this.config.features.headless && this.config.uploader.route === '/')
return this.nextServer.render(req.raw, reply.raw, '/dashboard');
const file = await this.prisma.file.findFirst({
@ -12,16 +11,13 @@ export default async function uploadsRoute(this: FastifyInstance, req: FastifyRe
OR: [{ name: id }, { name: decodeURI(id) }, { invisible: { invis: decodeURI(encodeURI(id)) } }],
},
});
if (!file) return reply.rawFile(id);
if (!file) return reply.notFound();
const failed = await reply.preFile(file);
if (failed) return reply.notFound();
const ext = file.name.split('.').pop();
if (file.password || file.embed || file.mimetype.startsWith('text/') || Object.keys(exts).includes(ext))
return reply.redirect(`/view/${file.name}`);
else return reply.dbFile(file);
return this.nextServer.render(req.raw, reply.raw, `/view/${file.name}`);
}
export async function uploadsRouteOnResponse(