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:
parent
9edb38fedc
commit
7ef20827fb
6 changed files with 51 additions and 148 deletions
|
@ -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>;
|
||||
}
|
||||
}
|
|
@ -30,6 +30,6 @@ export default fastifyPlugin(preFileDecorator, {
|
|||
|
||||
declare module 'fastify' {
|
||||
interface FastifyReply {
|
||||
preFile: (file: File) => Promise<boolean>;
|
||||
preFile: (file: Partial<File>) => Promise<boolean>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Add table
Reference in a new issue