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:
@@ -32,7 +32,7 @@ model attendance {
|
||||
users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "attendance_ibfk_1")
|
||||
attendance_project_logs attendance_project_logs[]
|
||||
|
||||
@@index([user_id, shift_date], map: "idx_attendance_user_date")
|
||||
@@unique([user_id, shift_date], map: "idx_attendance_user_date")
|
||||
@@index([user_id, departure_time], map: "idx_attendance_user_departure")
|
||||
@@index([project_id], map: "idx_project_id")
|
||||
}
|
||||
@@ -46,6 +46,7 @@ model attendance_project_logs {
|
||||
hours Int? @db.UnsignedInt
|
||||
minutes Int? @db.UnsignedInt
|
||||
attendance attendance @relation(fields: [attendance_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
||||
projects projects? @relation(fields: [project_id], references: [id], onDelete: SetNull, onUpdate: NoAction)
|
||||
|
||||
@@index([attendance_id], map: "idx_attendance_project_logs_aid")
|
||||
@@index([project_id], map: "idx_project_id")
|
||||
@@ -104,7 +105,7 @@ model company_settings {
|
||||
quotation_prefix String? @db.VarChar(20)
|
||||
default_currency String? @default("CZK") @db.VarChar(10)
|
||||
default_vat_rate Decimal? @default(21.00) @db.Decimal(5, 2)
|
||||
uuid String? @db.VarChar(36)
|
||||
uuid String? @unique @db.VarChar(36)
|
||||
modified_at DateTime? @db.DateTime(0)
|
||||
is_deleted Boolean? @default(false)
|
||||
sync_version Int? @default(0)
|
||||
@@ -165,7 +166,7 @@ model invoice_items {
|
||||
|
||||
model invoices {
|
||||
id Int @id @default(autoincrement())
|
||||
invoice_number String? @db.VarChar(50)
|
||||
invoice_number String? @unique(map: "idx_invoices_number_unique") @db.VarChar(50)
|
||||
order_id Int?
|
||||
customer_id Int?
|
||||
status String? @default("issued") @db.VarChar(30)
|
||||
@@ -288,7 +289,7 @@ model order_sections {
|
||||
|
||||
model orders {
|
||||
id Int @id @default(autoincrement())
|
||||
order_number String? @db.VarChar(50)
|
||||
order_number String? @unique(map: "idx_orders_number_unique") @db.VarChar(50)
|
||||
customer_order_number String? @db.VarChar(100)
|
||||
attachment_data Bytes?
|
||||
attachment_name String? @db.VarChar(255)
|
||||
@@ -340,7 +341,7 @@ model project_notes {
|
||||
|
||||
model projects {
|
||||
id Int @id @default(autoincrement())
|
||||
project_number String? @db.VarChar(50)
|
||||
project_number String? @unique @db.VarChar(50)
|
||||
name String? @db.VarChar(255)
|
||||
customer_id Int?
|
||||
responsible_user_id Int?
|
||||
@@ -352,6 +353,7 @@ model projects {
|
||||
notes String? @db.Text
|
||||
created_at DateTime? @default(now()) @db.DateTime(0)
|
||||
modified_at DateTime? @db.DateTime(0)
|
||||
attendance_project_logs attendance_project_logs[]
|
||||
project_notes project_notes[]
|
||||
users users? @relation(fields: [responsible_user_id], references: [id], onUpdate: NoAction, map: "fk_projects_responsible_user")
|
||||
customers customers? @relation(fields: [customer_id], references: [id], onUpdate: NoAction, map: "projects_ibfk_1")
|
||||
@@ -385,7 +387,7 @@ model quotation_items {
|
||||
|
||||
model quotations {
|
||||
id Int @id @default(autoincrement())
|
||||
quotation_number String? @db.VarChar(50)
|
||||
quotation_number String? @unique @db.VarChar(50)
|
||||
project_code String? @db.VarChar(50)
|
||||
customer_id Int?
|
||||
created_at DateTime? @default(now()) @db.DateTime(0)
|
||||
@@ -434,7 +436,7 @@ model received_invoices {
|
||||
file_mime String? @db.VarChar(100)
|
||||
file_size Int? @db.UnsignedInt
|
||||
notes String? @db.Text
|
||||
uploaded_by Int? @db.UnsignedInt
|
||||
uploaded_by Int?
|
||||
created_at DateTime @default(now()) @db.DateTime(0)
|
||||
modified_at DateTime @default(now()) @db.DateTime(0)
|
||||
|
||||
@@ -446,7 +448,7 @@ model received_invoices {
|
||||
/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
|
||||
model refresh_tokens {
|
||||
id Int @id @default(autoincrement()) @db.UnsignedInt
|
||||
user_id Int @db.UnsignedInt
|
||||
user_id Int
|
||||
token_hash String @unique(map: "token_hash") @db.VarChar(64)
|
||||
expires_at DateTime @db.DateTime(0)
|
||||
replaced_at DateTime? @db.DateTime(0)
|
||||
|
||||
Reference in New Issue
Block a user