cebcf4f1f5
**Small Security Issue:** CSV exports were vulnerable to formula injection attacks when users entered values starting with =, +, -, or @. (only happens if a logged-in user injects corrupted data) Solution: - Added ZWJ (Zero-Width Joiner) protection that prefixes dangerous values with invisible Unicode character - This is the best way to preserve original data while preventing Excel from executing formulas - Added import cleanup to restore original values when re-importing Changes: - New sanitizeValueForCSVExport() function for security - Updated all CSV export paths to use both security + formatting functions - Added comprehensive tests covering attack vectors and international characters - Also added cursor rules for better code consistency --------- Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
46 lines
1.4 KiB
TypeScript
46 lines
1.4 KiB
TypeScript
import { useRecoilCallback } from 'recoil';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
import { pageLayoutCurrentLayoutsState } from '../states/pageLayoutCurrentLayoutsState';
|
|
import { pageLayoutDraftState } from '../states/pageLayoutDraftState';
|
|
import { type PageLayoutTab } from '../states/savedPageLayoutsState';
|
|
import { createEmptyTabLayout } from '../utils/createEmptyTabLayout';
|
|
|
|
export const usePageLayoutTabCreate = () => {
|
|
const handleCreateTab = useRecoilCallback(
|
|
({ snapshot, set }) =>
|
|
(title?: string): string => {
|
|
const pageLayoutDraft = snapshot
|
|
.getLoadable(pageLayoutDraftState)
|
|
.getValue();
|
|
|
|
const newTabId = `tab-${uuidv4()}`;
|
|
const newTab: PageLayoutTab = {
|
|
id: newTabId,
|
|
title: title || `Tab ${pageLayoutDraft.tabs.length + 1}`,
|
|
position: pageLayoutDraft.tabs.length,
|
|
pageLayoutId: '',
|
|
widgets: [],
|
|
createdAt: new Date().toISOString(),
|
|
updatedAt: new Date().toISOString(),
|
|
deletedAt: null,
|
|
};
|
|
|
|
const updatedTabs = [...pageLayoutDraft.tabs, newTab];
|
|
|
|
set(pageLayoutDraftState, (prev) => ({
|
|
...prev,
|
|
tabs: updatedTabs,
|
|
}));
|
|
|
|
set(pageLayoutCurrentLayoutsState, (prev) =>
|
|
createEmptyTabLayout(prev, newTabId),
|
|
);
|
|
|
|
return newTabId;
|
|
},
|
|
[],
|
|
);
|
|
|
|
return { handleCreateTab };
|
|
};
|