security: fix all Critical and High findings from FLAWS_REPORT audit
- Auth: pessimistic locking on login tokens and refresh token rotation, backup code attempt counter, rate limiting verification - Schema: unique constraints on business numbers, FK relations, unsigned/signed alignment, attendance duplicate prevention - Invoices/PDFs: DOMPurify sanitization, bounded queries in stats and alerts, VAT rounding, Puppeteer error handling - Orders/Offers: transactional parent+child creation, Zod NaN refinement, status enums, uniqueness checks - Projects/Files: path traversal protection, streamed uploads, permission guards, query param validation - Attendance/HR: duplicate checks, ownership validation, GPS restrictions, trip distance validation - Frontend: modal lock reference counting, XSS escaping in print HTML, ref mutation fixes, accessibility attributes Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -6,12 +6,14 @@ const OrderItemSchema = z.object({
|
||||
quantity: z
|
||||
.union([z.number(), z.string()])
|
||||
.transform((v) => Number(v) || 1)
|
||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
||||
.optional()
|
||||
.default(1),
|
||||
unit: z.string().nullish(),
|
||||
unit_price: z
|
||||
.union([z.number(), z.string()])
|
||||
.transform((v) => Number(v) || 0)
|
||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
||||
.optional()
|
||||
.default(0),
|
||||
is_included_in_total: z
|
||||
@@ -21,6 +23,7 @@ const OrderItemSchema = z.object({
|
||||
position: z
|
||||
.union([z.number(), z.string()])
|
||||
.transform((v) => Number(v))
|
||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
||||
.optional(),
|
||||
});
|
||||
|
||||
@@ -31,11 +34,15 @@ const OrderSectionSchema = z.object({
|
||||
position: z
|
||||
.union([z.number(), z.string()])
|
||||
.transform((v) => Number(v))
|
||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
||||
.optional(),
|
||||
});
|
||||
|
||||
export const CreateOrderFromQuotationSchema = z.object({
|
||||
quotationId: z.union([z.number(), z.string()]).transform((v) => Number(v)),
|
||||
quotationId: z
|
||||
.union([z.number(), z.string()])
|
||||
.transform((v) => Number(v))
|
||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" }),
|
||||
customerOrderNumber: z.string().optional().default(""),
|
||||
});
|
||||
|
||||
@@ -45,17 +52,23 @@ export const CreateOrderSchema = z.object({
|
||||
quotation_id: z
|
||||
.union([z.number(), z.string()])
|
||||
.transform((v) => Number(v))
|
||||
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||
.nullish(),
|
||||
customer_id: z
|
||||
.union([z.number(), z.string()])
|
||||
.transform((v) => Number(v))
|
||||
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||
.nullish(),
|
||||
status: z.string().optional().default("prijata"),
|
||||
status: z
|
||||
.enum(["prijata", "v_realizaci", "dokoncena", "zrusena"])
|
||||
.optional()
|
||||
.default("prijata"),
|
||||
currency: z.string().optional().default("CZK"),
|
||||
language: z.string().optional().default("cs"),
|
||||
vat_rate: z
|
||||
.union([z.number(), z.string()])
|
||||
.transform((v) => Number(v))
|
||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
||||
.optional()
|
||||
.default(21.0),
|
||||
apply_vat: z
|
||||
@@ -65,6 +78,7 @@ export const CreateOrderSchema = z.object({
|
||||
exchange_rate: z
|
||||
.union([z.number(), z.string()])
|
||||
.transform((v) => Number(v))
|
||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
||||
.optional()
|
||||
.default(1.0),
|
||||
scope_title: z.string().nullish(),
|
||||
@@ -76,7 +90,7 @@ export const CreateOrderSchema = z.object({
|
||||
|
||||
export const UpdateOrderSchema = z.object({
|
||||
customer_order_number: z.string().nullish(),
|
||||
status: z.string().optional(),
|
||||
status: z.enum(["prijata", "v_realizaci", "dokoncena", "zrusena"]).optional(),
|
||||
currency: z.string().optional(),
|
||||
language: z.string().optional(),
|
||||
scope_title: z.string().nullish(),
|
||||
@@ -86,6 +100,7 @@ export const UpdateOrderSchema = z.object({
|
||||
vat_rate: z
|
||||
.union([z.number(), z.string()])
|
||||
.transform((v) => Number(v))
|
||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
||||
.optional(),
|
||||
apply_vat: z
|
||||
.preprocess((v) => v === true || v === 1 || v === "1", z.boolean())
|
||||
|
||||
Reference in New Issue
Block a user