mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: resolve 14 security, correctness, and robustness issues found during QA sweep
Security fixes:
- Add auth + ownership check to thumbnail endpoint (was unauthenticated)
- Validate ExifTool fieldsToRemove against safe tag name pattern
- Add SVG sanitization to pipeline execute and batch endpoints
- Replace basename() with sanitizeFilename() in 16 tool routes
- Escape SQL LIKE wildcards in file search to prevent pattern injection
- Improve settings HTML tag validation pattern
Bug fixes:
- Skip autoOrient for SVG inputs in pipeline (prevents misinterpretation)
- Remove double-encode in compress targetSize (was degrading quality)
- Fix bg-effects alpha value from 255 to 1.0 (Sharp expects float)
- Guard download stream error handler against headers-already-sent race
- Use O_EXCL atomic file creation for install lock (fixes TOCTOU race)
- Truncate collage file array to template image count
UX fixes:
- Accept empty JSON bodies on POST endpoints (install/uninstall)
- Custom JSON content type parser that treats empty body as {}
This commit is contained in:
@@ -124,7 +124,8 @@ export async function userFileRoutes(app: FastifyInstance): Promise<void> {
|
||||
}
|
||||
|
||||
if (search) {
|
||||
conditions.push(like(schema.userFiles.originalName, `%${search}%`));
|
||||
const escaped = search.replace(/[%_\\]/g, "\\$&");
|
||||
conditions.push(like(schema.userFiles.originalName, `%${escaped}%`));
|
||||
}
|
||||
|
||||
const rows = db
|
||||
@@ -335,7 +336,9 @@ export async function userFileRoutes(app: FastifyInstance): Promise<void> {
|
||||
|
||||
const stream = createReadStream(filePath);
|
||||
stream.on("error", () => {
|
||||
reply.status(404).send({ error: "File not found on disk" });
|
||||
if (!reply.raw.headersSent) {
|
||||
reply.status(404).send({ error: "File not found on disk" });
|
||||
}
|
||||
});
|
||||
|
||||
return reply
|
||||
@@ -356,11 +359,14 @@ export async function userFileRoutes(app: FastifyInstance): Promise<void> {
|
||||
app.get(
|
||||
"/api/v1/files/:id/thumbnail",
|
||||
async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply) => {
|
||||
const user = requireAuth(request, reply);
|
||||
if (!user) return;
|
||||
|
||||
const { id } = request.params;
|
||||
|
||||
const file = db.select().from(schema.userFiles).where(eq(schema.userFiles.id, id)).get();
|
||||
|
||||
if (!file) {
|
||||
if (!file || (file.userId !== user.id && !hasEffectivePermission(user, "files:all"))) {
|
||||
return reply.status(404).send({ error: "File not found" });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user