Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions public/_redirects
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* /index.html 200
3 changes: 2 additions & 1 deletion src/stores/aiStore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand';
import { scopedKey } from '../utils/visitorId';
import { persist } from 'zustand/middleware';

/**
Expand Down Expand Up @@ -417,7 +418,7 @@ Format as an actionable plan that can be imported into a remediation tracker.`;
}
}),
{
name: 'csf-ai-storage',
name: scopedKey('csf-ai-storage'),
partialize: (state) => ({
llmProvider: state.llmProvider,
dataMode: state.dataMode,
Expand Down
3 changes: 2 additions & 1 deletion src/stores/artifactStore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand';
import { scopedKey } from '../utils/visitorId';
import { persist } from 'zustand/middleware';
import Papa from 'papaparse';
import { v4 as uuidv4 } from 'uuid';
Expand Down Expand Up @@ -378,7 +379,7 @@ const useArtifactStore = create(
}
}),
{
name: 'csf-artifacts-storage',
name: scopedKey('csf-artifacts-storage'),
version: 5,
migrate: (persistedState, version) => {
// Version 2: Added link, complianceRequirement, controlId, type, jiraKey fields
Expand Down
3 changes: 2 additions & 1 deletion src/stores/assessmentsStore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand';
import { scopedKey } from '../utils/visitorId';
import { persist } from 'zustand/middleware';
import Papa from 'papaparse';
import { v4 as uuidv4 } from 'uuid';
Expand Down Expand Up @@ -1562,7 +1563,7 @@ const useAssessmentsStore = create(
}
}),
{
name: 'csf-assessments-storage',
name: scopedKey('csf-assessments-storage'),
version: 7,
migrate: (persistedState, version) => {
// Version 1: Migrate observations to quarterly structure
Expand Down
3 changes: 2 additions & 1 deletion src/stores/auditLogStore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand';
import { scopedKey } from '../utils/visitorId';
import { persist } from 'zustand/middleware';
import { v4 as uuidv4 } from 'uuid';

Expand Down Expand Up @@ -53,7 +54,7 @@ const useAuditLogStore = create(
URL.revokeObjectURL(url);
}
}),
{ name: 'csf-audit-log' }
{ name: scopedKey('csf-audit-log') }
)
);

Expand Down
3 changes: 2 additions & 1 deletion src/stores/controlsStore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand';
import { scopedKey } from '../utils/visitorId';
import { persist } from 'zustand/middleware';
import Papa from 'papaparse';
import { sanitizeInput, escapeCSVValue } from '../utils/sanitize';
Expand Down Expand Up @@ -471,7 +472,7 @@ const useControlsStore = create(
}
}),
{
name: 'csf-controls-storage',
name: scopedKey('csf-controls-storage'),
version: 5,
migrate: (persistedState, version) => {
// Version 5: Default controls from Alma Security example data
Expand Down
3 changes: 2 additions & 1 deletion src/stores/csfStore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand';
import { scopedKey } from '../utils/visitorId';
import { persist } from 'zustand/middleware';
import { parseUserInfo, findOrCreateUser } from '../utils/userUtils';
import { sanitizeInput } from '../utils/sanitize';
Expand Down Expand Up @@ -252,7 +253,7 @@ const useCSFStore = create(
},
}),
{
name: 'csf-data-storage',
name: scopedKey('csf-data-storage'),
version: 2,
migrate: (persistedState, version) => {
// Version 2: Force re-download of CSV to get proper owner assignments
Expand Down
3 changes: 2 additions & 1 deletion src/stores/evaluationsStore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand';
import { scopedKey } from '../utils/visitorId';
import { persist } from 'zustand/middleware';
import { sanitizeInput } from '../utils/sanitize';

Expand Down Expand Up @@ -453,7 +454,7 @@ const useEvaluationsStore = create(
}
}),
{
name: 'csf-evaluations-storage',
name: scopedKey('csf-evaluations-storage'),
version: 1,
partialize: (state) => ({
evaluations: state.evaluations,
Expand Down
3 changes: 2 additions & 1 deletion src/stores/findingsStore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand';
import { scopedKey } from '../utils/visitorId';
import { persist } from 'zustand/middleware';
import Papa from 'papaparse';
import { v4 as uuidv4 } from 'uuid';
Expand Down Expand Up @@ -357,7 +358,7 @@ const useFindingsStore = create(
}
}),
{
name: 'csf-findings-storage',
name: scopedKey('csf-findings-storage'),
version: 3,
migrate: (persistedState, version) => {
// Version 2: Added default findings for new installations
Expand Down
3 changes: 2 additions & 1 deletion src/stores/frameworksStore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand';
import { scopedKey } from '../utils/visitorId';
import { persist } from 'zustand/middleware';

// Default frameworks - used for initial state and migrations
Expand Down Expand Up @@ -194,7 +195,7 @@ const useFrameworksStore = create(
}
}),
{
name: 'csf-frameworks-storage',
name: scopedKey('csf-frameworks-storage'),
version: 5,
migrate: (persistedState, version) => {
// Version 2: Reset to new default frameworks (removed SOC2, HIPAA, PCI-DSS; updated names; added source)
Expand Down
3 changes: 2 additions & 1 deletion src/stores/requirementsStore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand';
import { scopedKey } from '../utils/visitorId';
import { persist } from 'zustand/middleware';
import Papa from 'papaparse';
import { escapeCSVValue } from '../utils/sanitize';
Expand Down Expand Up @@ -418,7 +419,7 @@ const useRequirementsStore = create(
}
}),
{
name: 'csf-requirements-storage',
name: scopedKey('csf-requirements-storage'),
partialize: (state) => ({
requirements: state.requirements
})
Expand Down
3 changes: 2 additions & 1 deletion src/stores/uiStore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand';
import { scopedKey } from '../utils/visitorId';
import { persist } from 'zustand/middleware';

const useUIStore = create(
Expand Down Expand Up @@ -103,7 +104,7 @@ const useUIStore = create(
}),
}),
{
name: 'csf-ui-storage',
name: scopedKey('csf-ui-storage'),
partialize: (state) => ({
darkMode: state.darkMode,
itemsPerPage: state.itemsPerPage,
Expand Down
3 changes: 2 additions & 1 deletion src/stores/userStore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand';
import { scopedKey } from '../utils/visitorId';
import { persist } from 'zustand/middleware';
import { v4 as uuidv4 } from 'uuid';

Expand Down Expand Up @@ -132,7 +133,7 @@ const useUserStore = create(
},
}),
{
name: 'csf-users-storage',
name: scopedKey('csf-users-storage'),
version: 2,
migrate: (persistedState, version) => {
// Version 2: Ensure default users have stable IDs
Expand Down
15 changes: 15 additions & 0 deletions src/utils/visitorId.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Generate a stable per-visitor ID scoped to this browser session.
// This prevents localStorage cross-contamination between demo visitors.
const VISITOR_KEY = 'csf-visitor-id';

function getVisitorId() {
let id = localStorage.getItem(VISITOR_KEY);
if (!id) {
id = 'v-' + Math.random().toString(36).slice(2, 11);
localStorage.setItem(VISITOR_KEY, id);
}
return id;
}

export const visitorId = getVisitorId();
export const scopedKey = (name) => `${name}-${visitorId}`;
Loading