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:
@@ -76,6 +76,7 @@ export default function Settings() {
|
||||
const navigate = useNavigate();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [roles, setRoles] = useState<Role[]>([]);
|
||||
const [users, setUsers] = useState<{ role_id: number }[]>([]);
|
||||
const [, setAllPermissions] = useState<Permission[]>([]);
|
||||
const [permissionGroups, setPermissionGroups] = useState<
|
||||
Record<string, Permission[]>
|
||||
@@ -161,12 +162,14 @@ export default function Settings() {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const [rolesRes, permsRes] = await Promise.all([
|
||||
const [rolesRes, permsRes, usersRes] = await Promise.all([
|
||||
apiFetch(`${API_BASE}/roles`),
|
||||
apiFetch(`${API_BASE}/roles/permissions`),
|
||||
apiFetch(`${API_BASE}/users`),
|
||||
]);
|
||||
const rolesResult = await rolesRes.json();
|
||||
const permsResult = await permsRes.json();
|
||||
const usersResult = await usersRes.json();
|
||||
|
||||
if (rolesResult.success) {
|
||||
setRoles(Array.isArray(rolesResult.data) ? rolesResult.data : []);
|
||||
@@ -188,6 +191,10 @@ export default function Settings() {
|
||||
}
|
||||
setPermissionGroups(groups);
|
||||
}
|
||||
|
||||
if (usersResult.success) {
|
||||
setUsers(Array.isArray(usersResult.data) ? usersResult.data : []);
|
||||
}
|
||||
} catch {
|
||||
alert.error("Chyba připojení");
|
||||
} finally {
|
||||
@@ -808,7 +815,7 @@ export default function Settings() {
|
||||
</td>
|
||||
<td>
|
||||
<span className="admin-badge admin-badge-secondary">
|
||||
{0}
|
||||
{users.filter((u) => u.role_id === role.id).length}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
@@ -838,16 +845,21 @@ export default function Settings() {
|
||||
}
|
||||
className="admin-btn-icon danger"
|
||||
title={
|
||||
0 > 0
|
||||
users.filter((u) => u.role_id === role.id)
|
||||
.length > 0
|
||||
? "Nelze smazat roli s přiřazenými uživateli"
|
||||
: "Smazat"
|
||||
}
|
||||
aria-label={
|
||||
0 > 0
|
||||
users.filter((u) => u.role_id === role.id)
|
||||
.length > 0
|
||||
? "Nelze smazat roli s přiřazenými uživateli"
|
||||
: "Smazat"
|
||||
}
|
||||
disabled={0 > 0}
|
||||
disabled={
|
||||
users.filter((u) => u.role_id === role.id)
|
||||
.length > 0
|
||||
}
|
||||
>
|
||||
<svg
|
||||
width="16"
|
||||
|
||||
Reference in New Issue
Block a user