security: fix all Medium findings from FLAWS_REPORT audit
- Auth: TOTP replay protection with counter tracking, constant-time backup code comparison, atomic lockout increment, per-token logout - Invoices/PDFs: net-based VAT calculation, dangerous URL scheme stripping in cleanQuillHtml, orders-pdf error handling - Orders: reject item changes on status transition, cascading delete cleanup, take:1 with orderBy - Projects: atomic rename collision handling, MIME/extension validation, empty customer name rejection - Attendance: Czech public holiday awareness in frontend fund calculation, leave_hours 0 handling, invalid date NaN guard, bounded per-month queries in workfund - Users/Admin: profile audit logging + password validation, session revocation guard, session ID validation, dashboard DB aggregation, soft-deleted record protection in scope templates - Frontend: FormField label linkage, Pagination ARIA, error handling in OrderConfirmationModal, 401 propagation, GPS emoji hidden from screen readers, table sort state fix, geolocation race/abort cleanup, Leaflet popup DOM safety, Vehicles toggleActive minimal body, CompanySettings ref mutation fix, OfferDetail unlock abort, AttendanceBalances combined fetches - Utils: env validation, Puppeteer concurrency mutex, invoice alert cron cleanup on shutdown, body limit alignment, TOTP error logging, trustProxy from env, symlink rejection, rate cache Map usage Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -97,7 +97,11 @@ export async function listOrders(params: ListOrdersParams) {
|
||||
order_items: { orderBy: { position: "asc" } },
|
||||
order_sections: { orderBy: { position: "asc" } },
|
||||
quotations: { select: { quotation_number: true, project_code: true } },
|
||||
invoices: { select: { id: true, invoice_number: true }, take: 1 },
|
||||
invoices: {
|
||||
select: { id: true, invoice_number: true },
|
||||
take: 1,
|
||||
orderBy: { id: "desc" },
|
||||
},
|
||||
},
|
||||
}),
|
||||
prisma.orders.count({ where }),
|
||||
@@ -410,6 +414,16 @@ export async function updateOrder(id: number, body: UpdateOrderData) {
|
||||
status: 400,
|
||||
} as const;
|
||||
}
|
||||
if (
|
||||
body.status !== undefined &&
|
||||
(String(body.status) === "dokoncena" ||
|
||||
String(body.status) === "stornovana")
|
||||
) {
|
||||
return {
|
||||
error: "Nelze upravit položky při změně stavu na dokončeno/storno",
|
||||
status: 400,
|
||||
} as const;
|
||||
}
|
||||
await prisma.$transaction(async (tx) => {
|
||||
await tx.orders.update({ where: { id }, data });
|
||||
|
||||
@@ -504,6 +518,10 @@ export async function deleteOrder(id: number) {
|
||||
await prisma.projects.deleteMany({ where: { order_id: id } });
|
||||
}
|
||||
|
||||
// Explicitly clean up child rows
|
||||
await prisma.order_items.deleteMany({ where: { order_id: id } });
|
||||
await prisma.order_sections.deleteMany({ where: { order_id: id } });
|
||||
|
||||
await prisma.orders.delete({ where: { id } });
|
||||
|
||||
const releasedYears = new Set<number>();
|
||||
|
||||
Reference in New Issue
Block a user