@jmruthers/pace-core 0.5.135 → 0.5.136
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DataTable-C7GaRZye.d.ts → DataTable-CWAZZcXC.d.ts} +1 -1
- package/dist/{DataTable-A36PJG6N.js → DataTable-CYOHOX3O.js} +25 -13
- package/dist/{PublicLoadingSpinner-CUAnTvcg.d.ts → EventLogo-801uofbR.d.ts} +51 -135
- package/dist/UnifiedAuthProvider-5E5TUNMS.js +17 -0
- package/dist/{UnifiedAuthProvider-BVKmQd9u.d.ts → UnifiedAuthProvider-DJxGTftH.d.ts} +1 -1
- package/dist/{api-TNIBJWLM.js → api-45XYYO2A.js} +4 -3
- package/dist/{audit-T36HM7IM.js → audit-64X3VJXB.js} +3 -2
- package/dist/{chunk-CTJRBUX2.js → chunk-2TWNJ46Y.js} +2 -2
- package/dist/{chunk-UJI6WSMD.js → chunk-444EZN6N.js} +3 -3
- package/dist/chunk-444EZN6N.js.map +1 -0
- package/dist/{chunk-3CG5L6RN.js → chunk-4MT5BGGL.js} +90 -73
- package/dist/chunk-4MT5BGGL.js.map +1 -0
- package/dist/{chunk-PYUXFQJ3.js → chunk-56XJ3TU6.js} +2 -2
- package/dist/chunk-56XJ3TU6.js.map +1 -0
- package/dist/chunk-5DPZ5EAT.js +60 -0
- package/dist/chunk-5DPZ5EAT.js.map +1 -0
- package/dist/{chunk-66C4BSAY.js → chunk-ANBQRTPX.js} +9 -2
- package/dist/chunk-ANBQRTPX.js.map +1 -0
- package/dist/chunk-APIBCTL2.js +670 -0
- package/dist/chunk-APIBCTL2.js.map +1 -0
- package/dist/{chunk-GKHF54DI.js → chunk-BESYRHQM.js} +10 -4
- package/dist/chunk-BESYRHQM.js.map +1 -0
- package/dist/{chunk-WP5I5GLN.js → chunk-BVYWGZVV.js} +112 -97
- package/dist/chunk-BVYWGZVV.js.map +1 -0
- package/dist/{chunk-GEVIB2UB.js → chunk-ERISIBYU.js} +14 -5
- package/dist/chunk-ERISIBYU.js.map +1 -0
- package/dist/{chunk-CQZU6TFE.js → chunk-FHWWBIHA.js} +100 -62
- package/dist/chunk-FHWWBIHA.js.map +1 -0
- package/dist/{chunk-O3NWNXDY.js → chunk-FMUCXFII.js} +2 -2
- package/dist/chunk-FMUCXFII.js.map +1 -0
- package/dist/{chunk-GVDR7WNV.js → chunk-HJGGOMQ6.js} +194 -518
- package/dist/chunk-HJGGOMQ6.js.map +1 -0
- package/dist/{chunk-BDZUMRBD.js → chunk-K2WWTH7O.js} +13 -6
- package/dist/chunk-K2WWTH7O.js.map +1 -0
- package/dist/{chunk-BYXRHAIF.js → chunk-L6PGMCMD.js} +23 -14
- package/dist/chunk-L6PGMCMD.js.map +1 -0
- package/dist/chunk-LMC26NLJ.js +84 -0
- package/dist/chunk-LMC26NLJ.js.map +1 -0
- package/dist/{chunk-M6DDYFUD.js → chunk-LS353YLY.js} +19 -16
- package/dist/chunk-LS353YLY.js.map +1 -0
- package/dist/{chunk-ZYZCRSBD.js → chunk-LTV3XIJJ.js} +16 -11
- package/dist/chunk-LTV3XIJJ.js.map +1 -0
- package/dist/{chunk-HMNOSGVA.js → chunk-NOHEVYVX.js} +377 -666
- package/dist/chunk-NOHEVYVX.js.map +1 -0
- package/dist/{chunk-JCQZ6LA7.js → chunk-Q5QRDWKI.js} +9 -3
- package/dist/chunk-Q5QRDWKI.js.map +1 -0
- package/dist/chunk-S5OFRT4M.js +94 -0
- package/dist/chunk-S5OFRT4M.js.map +1 -0
- package/dist/{chunk-3DBFLLLU.js → chunk-SBVILCCA.js} +14 -9
- package/dist/chunk-SBVILCCA.js.map +1 -0
- package/dist/{chunk-TGIY2AR2.js → chunk-SL2YQDR6.js} +4 -3
- package/dist/{chunk-TGIY2AR2.js.map → chunk-SL2YQDR6.js.map} +1 -1
- package/dist/{chunk-VZ5OR6HD.js → chunk-TVYPTYOY.js} +55 -179
- package/dist/chunk-TVYPTYOY.js.map +1 -0
- package/dist/{chunk-ZV77RZMU.js → chunk-XARJS7CD.js} +2 -2
- package/dist/chunk-XDNLUEXI.js +138 -0
- package/dist/chunk-XDNLUEXI.js.map +1 -0
- package/dist/{chunk-F64FFPOZ.js → chunk-YLKIDTUK.js} +26 -20
- package/dist/chunk-YLKIDTUK.js.map +1 -0
- package/dist/{chunk-5F3NDPJV.js → chunk-ZZ2SS7NI.js} +10 -5
- package/dist/chunk-ZZ2SS7NI.js.map +1 -0
- package/dist/components.d.ts +7 -287
- package/dist/components.js +26 -157
- package/dist/components.js.map +1 -1
- package/dist/{file-reference-C9isKNPn.d.ts → file-reference-C6Gkn77H.d.ts} +1 -1
- package/dist/{formatting-DFcCxUEk.d.ts → formatting-CvUXy2mF.d.ts} +1 -1
- package/dist/hooks.d.ts +3 -3
- package/dist/hooks.js +22 -16
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +101 -9
- package/dist/index.js +43 -31
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +5 -4
- package/dist/rbac/index.js +13 -12
- package/dist/styles/index.js +2 -1
- package/dist/theming/runtime.d.ts +2 -19
- package/dist/theming/runtime.js +2 -1
- package/dist/{types-D5rqZQXk.d.ts → types-Dfz9dmVH.d.ts} +12 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -1
- package/dist/{useInactivityTracker-MRUU55XI.js → useInactivityTracker-TO6ZOF35.js} +3 -2
- package/dist/{usePublicRouteParams-Dyt1tzI9.d.ts → usePublicRouteParams-B7PabvuH.d.ts} +1 -1
- package/dist/utils.d.ts +195 -232
- package/dist/utils.js +173 -331
- package/dist/utils.js.map +1 -1
- package/dist/{validation-DnhrNMju.d.ts → validation-8npbysjg.d.ts} +26 -8
- package/dist/validation.d.ts +261 -10
- package/dist/validation.js +82 -440
- package/dist/validation.js.map +1 -1
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +6 -6
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +6 -6
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +7 -7
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +4 -4
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +29 -4
- package/docs/api/interfaces/DataAccessRecord.md +9 -9
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +18 -18
- package/docs/api/interfaces/DataTableColumn.md +61 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
- package/docs/api/interfaces/EmptyStateConfig.md +5 -5
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +14 -14
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +152 -0
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.md +8 -8
- package/docs/api/interfaces/FileDisplayProps.md +15 -15
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
- package/docs/api/interfaces/NavigationContextType.md +9 -9
- package/docs/api/interfaces/NavigationGuardProps.md +10 -10
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +7 -7
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +27 -27
- package/docs/api/interfaces/PaceLoginPageProps.md +4 -4
- package/docs/api/interfaces/PageAccessRecord.md +8 -8
- package/docs/api/interfaces/PagePermissionContextType.md +8 -8
- package/docs/api/interfaces/PagePermissionGuardProps.md +11 -11
- package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
- package/docs/api/interfaces/PaletteData.md +4 -4
- package/docs/api/interfaces/PermissionEnforcerProps.md +11 -11
- package/docs/api/interfaces/ProtectedRouteProps.md +6 -6
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
- package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +10 -10
- package/docs/api/interfaces/RouteConfig.md +10 -10
- package/docs/api/interfaces/SecureDataContextType.md +9 -9
- package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +21 -0
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +53 -53
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +9 -9
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
- package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
- package/docs/api/interfaces/UsePublicEventReturn.md +5 -5
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +9 -9
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +4 -4
- package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
- package/docs/api/interfaces/UserEventAccess.md +11 -11
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +514 -212
- package/docs/api-reference/components.md +106 -26
- package/docs/architecture/README.md +0 -2
- package/docs/implementation-guides/data-tables.md +277 -13
- package/docs/implementation-guides/forms.md +1 -16
- package/docs/implementation-guides/permission-enforcement.md +8 -2
- package/examples/README.md +30 -14
- package/examples/STRUCTURE.md +125 -0
- package/examples/components/DataTable/HierarchicalActionsExample.tsx +421 -0
- package/examples/components/DataTable/HierarchicalExample.tsx +475 -0
- package/examples/components/DataTable/InitialPageSizeExample.tsx +177 -0
- package/examples/components/DataTable/PerformanceExample.tsx +506 -0
- package/examples/components/DataTable/index.ts +13 -0
- package/examples/components/Dialog/BasicHtmlTest.tsx +55 -0
- package/examples/components/Dialog/DebugHtmlExample.tsx +68 -0
- package/examples/components/Dialog/HtmlDialogExample.tsx +202 -0
- package/examples/components/Dialog/ScrollableDialogExample.tsx +290 -0
- package/examples/components/Dialog/SimpleHtmlTest.tsx +61 -0
- package/examples/components/Dialog/SmartDialogExample.tsx +322 -0
- package/examples/components/Dialog/index.ts +15 -0
- package/examples/components/index.ts +11 -0
- package/examples/features/index.ts +12 -0
- package/examples/{public-pages → features/public-pages}/CorrectPublicPageImplementation.tsx +1 -1
- package/examples/{public-pages → features/public-pages}/PublicEventPage.tsx +1 -1
- package/examples/{public-pages → features/public-pages}/PublicPageApp.tsx +1 -1
- package/examples/{public-pages → features/public-pages}/PublicPageUsageExample.tsx +1 -1
- package/examples/index.ts +11 -3
- package/package.json +30 -10
- package/src/components/Alert/Alert.tsx +1 -1
- package/src/components/Avatar/Avatar.tsx +1 -1
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/Card/Card.tsx +1 -1
- package/src/components/Checkbox/Checkbox.tsx +1 -1
- package/src/components/DataTable/DataTable.test.tsx +1 -1
- package/src/components/DataTable/DataTable.tsx +1 -30
- package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +562 -0
- package/src/components/DataTable/__tests__/styles.test.ts +2 -2
- package/src/components/DataTable/components/ActionButtons.tsx +0 -15
- package/src/components/DataTable/components/DataTableCore.tsx +4 -185
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +1 -1
- package/src/components/DataTable/components/DataTableModals.tsx +1 -27
- package/src/components/DataTable/components/EditableRow.tsx +1 -1
- package/src/components/DataTable/components/ImportModal.tsx +2 -14
- package/src/components/DataTable/components/PaginationControls.tsx +1 -1
- package/src/components/DataTable/components/UnifiedTableBody.tsx +109 -82
- package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +1 -1
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +1 -1
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +1 -1
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +1 -1
- package/src/components/DataTable/examples/GroupingAggregationExample.tsx +273 -0
- package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +1 -1
- package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +1 -1
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +1 -1
- package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +1 -1
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +2 -23
- package/src/components/DataTable/index.ts +4 -0
- package/src/components/DataTable/styles.ts +1 -1
- package/src/components/DataTable/types.ts +13 -0
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +1 -1
- package/src/components/DataTable/utils/aggregationUtils.ts +161 -0
- package/src/components/DataTable/utils/exportUtils.ts +1 -1
- package/src/components/DataTable/utils/flexibleImport.ts +1 -11
- package/src/components/DataTable/utils/index.ts +1 -0
- package/src/components/DataTable/utils/paginationUtils.ts +1 -1
- package/src/components/Dialog/Dialog.tsx +2 -2
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +35 -7
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +5 -4
- package/src/components/EventSelector/EventSelector.tsx +3 -2
- package/src/components/FileDisplay/FileDisplay.tsx +2 -36
- package/src/components/FileUpload/FileUpload.test.tsx +2 -2
- package/src/components/FileUpload/FileUpload.tsx +2 -2
- package/src/components/Footer/Footer.tsx +1 -1
- package/src/components/Form/Form.test.tsx +4 -509
- package/src/components/Form/Form.tsx +1 -1
- package/src/components/Form/FormField.tsx +1 -1
- package/src/components/Form/index.ts +0 -12
- package/src/components/Header/Header.tsx +1 -1
- package/src/components/Input/Input.tsx +1 -1
- package/src/components/Label/Label.tsx +1 -1
- package/src/components/LoginForm/LoginForm.tsx +1 -1
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +19 -3
- package/src/components/NavigationMenu/NavigationMenu.tsx +9 -8
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +4 -3
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +14 -12
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +0 -16
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +0 -1
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -9
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +35 -3
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +13 -12
- package/src/components/PasswordReset/PasswordChangeForm.tsx +1 -1
- package/src/components/PasswordReset/index.ts +0 -2
- package/src/components/Progress/Progress.tsx +1 -1
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +35 -8
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -2
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +1 -1
- package/src/components/PublicLayout/PublicLoadingSpinner.tsx +1 -1
- package/src/components/PublicLayout/PublicPageContextChecker.tsx +44 -43
- package/src/components/PublicLayout/PublicPageFooter.tsx +1 -1
- package/src/components/PublicLayout/PublicPageHeader.tsx +1 -15
- package/src/components/PublicLayout/PublicPageProvider.tsx +3 -2
- package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +2 -0
- package/src/components/PublicLayout/index.ts +4 -2
- package/src/components/Select/Select.tsx +1 -1
- package/src/components/{SessionRestorationLoader.tsx → SessionRestorationLoader/SessionRestorationLoader.tsx} +3 -2
- package/src/components/SessionRestorationLoader/index.ts +3 -0
- package/src/components/Switch/Switch.tsx +1 -1
- package/src/components/Table/Table.tsx +1 -1
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/components/Tooltip/Tooltip.tsx +1 -1
- package/src/components/index.ts +4 -10
- package/src/hooks/__tests__/hooks.integration.test.tsx +37 -22
- package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +33 -17
- package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +28 -3
- package/src/hooks/__tests__/useFileDisplay.unit.test.ts +36 -9
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +26 -2
- package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +19 -6
- package/src/hooks/__tests__/usePermissionCache.simple.test.ts +17 -4
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +17 -4
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +26 -6
- package/src/hooks/__tests__/usePublicFileDisplay.test.ts +16 -6
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +3 -3
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +17 -3
- package/src/hooks/public/usePublicEvent.ts +7 -6
- package/src/hooks/public/usePublicEventLogo.ts +7 -4
- package/src/hooks/public/usePublicFileDisplay.ts +6 -150
- package/src/hooks/useComponentPerformance.ts +4 -1
- package/src/hooks/useDataTablePerformance.ts +4 -3
- package/src/hooks/useEventTheme.test.ts +18 -5
- package/src/hooks/useEventTheme.ts +4 -1
- package/src/hooks/useEvents.ts +2 -0
- package/src/hooks/useFileDisplay.ts +9 -8
- package/src/hooks/useFileReference.ts +4 -1
- package/src/hooks/useFileUrl.ts +4 -1
- package/src/hooks/useInactivityTracker.ts +5 -4
- package/src/hooks/useOrganisationSecurity.test.ts +33 -12
- package/src/hooks/useOrganisationSecurity.ts +8 -7
- package/src/hooks/usePerformanceMonitor.ts +6 -3
- package/src/hooks/usePermissionCache.ts +13 -6
- package/src/hooks/useSecureDataAccess.test.ts +2 -2
- package/src/hooks/useSecureDataAccess.ts +9 -8
- package/src/hooks/useSessionRestoration.ts +4 -1
- package/src/hooks/useStorage.ts +4 -1
- package/src/index.ts +16 -7
- package/src/providers/services/AuthServiceProvider.tsx +3 -2
- package/src/providers/services/EventServiceProvider.tsx +2 -1
- package/src/providers/services/InactivityServiceProvider.tsx +2 -1
- package/src/providers/services/OrganisationServiceProvider.tsx +2 -1
- package/src/providers/services/UnifiedAuthProvider.tsx +4 -3
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +22 -2
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +24 -2
- package/src/rbac/__tests__/cache-invalidation.test.ts +20 -6
- package/src/rbac/api.ts +5 -2
- package/src/rbac/audit-enhanced.ts +6 -6
- package/src/rbac/audit.test.ts +60 -38
- package/src/rbac/audit.ts +8 -8
- package/src/rbac/cache-invalidation.ts +7 -4
- package/src/rbac/components/EnhancedNavigationMenu.tsx +11 -5
- package/src/rbac/components/NavigationGuard.tsx +7 -3
- package/src/rbac/components/NavigationProvider.tsx +6 -3
- package/src/rbac/components/PagePermissionGuard.tsx +28 -16
- package/src/rbac/components/PagePermissionProvider.tsx +4 -1
- package/src/rbac/components/PermissionEnforcer.tsx +9 -3
- package/src/rbac/components/RoleBasedRouter.tsx +3 -1
- package/src/rbac/components/SecureDataProvider.tsx +7 -3
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +87 -61
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +83 -33
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +36 -13
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +2 -2
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +22 -8
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +19 -6
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +43 -17
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +42 -17
- package/src/rbac/engine.ts +15 -7
- package/src/rbac/hooks/usePermissions.ts +7 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +2 -2
- package/src/rbac/hooks/useResolvedScope.ts +10 -7
- package/src/rbac/permissions.ts +5 -2
- package/src/rbac/security.test.ts +27 -16
- package/src/rbac/security.ts +5 -4
- package/src/services/AuthService.ts +22 -21
- package/src/services/EventService.ts +12 -12
- package/src/services/InactivityService.ts +5 -4
- package/src/services/OrganisationService.ts +26 -25
- package/src/services/__tests__/AuthService.test.ts +51 -19
- package/src/services/__tests__/EventService.test.ts +37 -5
- package/src/services/__tests__/InactivityService.test.ts +38 -4
- package/src/services/__tests__/OrganisationService.test.ts +3 -8
- package/src/services/base/BaseService.ts +3 -1
- package/src/theming/__tests__/runtime.test.ts +21 -12
- package/src/theming/parseEventColours.ts +5 -19
- package/src/theming/runtime.ts +8 -4
- package/src/types/validation.ts +2 -29
- package/src/utils/__tests__/appConfig.unit.test.ts +1 -1
- package/src/utils/__tests__/audit.unit.test.ts +1 -1
- package/src/utils/__tests__/auth-utils.unit.test.ts +1 -1
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +19 -19
- package/src/utils/__tests__/cn.unit.test.ts +1 -1
- package/src/utils/__tests__/debugLogger.test.ts +1 -1
- package/src/utils/__tests__/deviceFingerprint.unit.test.ts +1 -1
- package/src/utils/__tests__/dynamicUtils.unit.test.ts +1 -1
- package/src/utils/__tests__/formatting.unit.test.ts +1 -1
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +1 -1
- package/src/utils/__tests__/logger.unit.test.ts +1 -1
- package/src/utils/__tests__/organisationContext.unit.test.ts +1 -1
- package/src/utils/__tests__/performanceBenchmark.test.ts +1 -1
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +1 -1
- package/src/utils/__tests__/permissionTypes.unit.test.ts +1 -1
- package/src/utils/__tests__/permissionUtils.unit.test.ts +1 -1
- package/src/utils/__tests__/sanitization.unit.test.ts +1 -1
- package/src/utils/__tests__/schemaUtils.unit.test.ts +1 -1
- package/src/utils/__tests__/secureDataAccess.unit.test.ts +1 -1
- package/src/utils/__tests__/secureErrors.unit.test.ts +33 -15
- package/src/utils/__tests__/secureStorage.unit.test.ts +1 -1
- package/src/utils/__tests__/security.unit.test.ts +40 -18
- package/src/utils/__tests__/securityMonitor.unit.test.ts +1 -1
- package/src/utils/__tests__/sessionTracking.unit.test.ts +40 -29
- package/src/utils/__tests__/validationUtils.unit.test.ts +19 -6
- package/src/utils/{appIdResolver.test.ts → app/appIdResolver.test.ts} +28 -30
- package/src/utils/{appIdResolver.ts → app/appIdResolver.ts} +8 -5
- package/src/utils/{appNameResolver.test.ts → app/appNameResolver.test.ts} +1 -1
- package/src/utils/{appNameResolver.ts → app/appNameResolver.ts} +5 -1
- package/src/utils/{organisationContext.ts → context/organisationContext.ts} +6 -3
- package/src/utils/{sessionTracking.ts → context/sessionTracking.ts} +11 -12
- package/src/utils/{logger.ts → core/logger.ts} +4 -2
- package/src/utils/{deviceFingerprint.ts → device/deviceFingerprint.ts} +1 -1
- package/src/utils/{lazyLoad.tsx → dynamic/lazyLoad.tsx} +2 -2
- package/src/utils/{file-reference.test.ts → file-reference/__tests__/file-reference.test.ts} +5 -5
- package/src/utils/{file-reference.ts → file-reference/index.ts} +20 -38
- package/src/utils/index.ts +32 -54
- package/src/utils/{secureErrors.ts → security/secureErrors.ts} +6 -3
- package/src/utils/{security.ts → security/security.ts} +5 -2
- package/src/utils/storage/__tests__/helpers.unit.test.ts +1 -4
- package/src/utils/storage/helpers.ts +15 -8
- package/src/{components/Dialog/utils/__tests__/safeHtml.unit.test.ts → utils/validation/__tests__/htmlSanitization.unit.test.ts} +9 -15
- package/src/{validation → utils/validation}/csrf.ts +1 -1
- package/src/{components/Dialog/utils/safeHtml.ts → utils/validation/htmlSanitization.ts} +9 -10
- package/src/utils/validation/index.ts +79 -0
- package/src/utils/{sanitization.ts → validation/sanitization.ts} +71 -2
- package/src/{validation/schemaUtils.ts → utils/validation/schema.ts} +11 -6
- package/src/{validation → utils/validation}/sqlInjectionProtection.ts +2 -0
- package/src/utils/{validationUtils.ts → validation/validationUtils.ts} +4 -1
- package/src/validation/index.ts +3 -34
- package/dist/UnifiedAuthProvider-CQDZRJIS.js +0 -16
- package/dist/chunk-24MKLB7U.js +0 -81
- package/dist/chunk-24MKLB7U.js.map +0 -1
- package/dist/chunk-3CG5L6RN.js.map +0 -1
- package/dist/chunk-3DBFLLLU.js.map +0 -1
- package/dist/chunk-5F3NDPJV.js.map +0 -1
- package/dist/chunk-66C4BSAY.js.map +0 -1
- package/dist/chunk-BDZUMRBD.js.map +0 -1
- package/dist/chunk-BYXRHAIF.js.map +0 -1
- package/dist/chunk-CDQ3PX7L.js +0 -18
- package/dist/chunk-CDQ3PX7L.js.map +0 -1
- package/dist/chunk-CQZU6TFE.js.map +0 -1
- package/dist/chunk-F64FFPOZ.js.map +0 -1
- package/dist/chunk-GEVIB2UB.js.map +0 -1
- package/dist/chunk-GKHF54DI.js.map +0 -1
- package/dist/chunk-GVDR7WNV.js.map +0 -1
- package/dist/chunk-HMNOSGVA.js.map +0 -1
- package/dist/chunk-JCQZ6LA7.js.map +0 -1
- package/dist/chunk-M6DDYFUD.js.map +0 -1
- package/dist/chunk-O3NWNXDY.js.map +0 -1
- package/dist/chunk-PYUXFQJ3.js.map +0 -1
- package/dist/chunk-UJI6WSMD.js.map +0 -1
- package/dist/chunk-VZ5OR6HD.js.map +0 -1
- package/dist/chunk-WP5I5GLN.js.map +0 -1
- package/dist/chunk-ZYZCRSBD.js.map +0 -1
- package/src/components/Dialog/README.md +0 -804
- package/src/components/Form/FormErrorSummary.tsx +0 -113
- package/src/components/Form/FormFieldset.tsx +0 -127
- package/src/components/Form/FormLiveRegion.tsx +0 -198
- package/src/components/PasswordReset/PasswordResetForm.test.tsx +0 -597
- package/src/components/PasswordReset/PasswordResetForm.tsx +0 -201
- package/src/components/PublicLayout/PublicPageDebugger.tsx +0 -104
- package/src/components/PublicLayout/PublicPageDiagnostic.tsx +0 -162
- package/src/components/PublicLayout/__tests__/PublicPageDebugger.test.tsx +0 -185
- package/src/examples/CorrectPublicPageImplementation.tsx +0 -304
- package/src/examples/PublicEventPage.tsx +0 -287
- package/src/examples/PublicPageApp.tsx +0 -321
- package/src/examples/PublicPageUsageExample.tsx +0 -218
- package/src/utils/schemaUtils.ts +0 -37
- package/src/validation/__tests__/common.unit.test.ts +0 -101
- package/src/validation/__tests__/csrf.unit.test.ts +0 -365
- package/src/validation/__tests__/passwordSchema.unit.test.ts +0 -203
- package/src/validation/__tests__/sanitization.unit.test.ts +0 -250
- package/src/validation/__tests__/schemaUtils.unit.test.ts +0 -451
- package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +0 -462
- package/src/validation/__tests__/user.unit.test.ts +0 -440
- package/src/validation/sanitization.ts +0 -96
- /package/dist/{DataTable-A36PJG6N.js.map → DataTable-CYOHOX3O.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-CQDZRJIS.js.map → UnifiedAuthProvider-5E5TUNMS.js.map} +0 -0
- /package/dist/{api-TNIBJWLM.js.map → api-45XYYO2A.js.map} +0 -0
- /package/dist/{audit-T36HM7IM.js.map → audit-64X3VJXB.js.map} +0 -0
- /package/dist/{chunk-CTJRBUX2.js.map → chunk-2TWNJ46Y.js.map} +0 -0
- /package/dist/{chunk-ZV77RZMU.js.map → chunk-XARJS7CD.js.map} +0 -0
- /package/dist/{useInactivityTracker-MRUU55XI.js.map → useInactivityTracker-TO6ZOF35.js.map} +0 -0
- /package/examples/{public-pages → features/public-pages}/index.ts +0 -0
- /package/examples/{RBAC → features/rbac}/CompleteRBACExample.tsx +0 -0
- /package/examples/{RBAC → features/rbac}/EventBasedApp.tsx +0 -0
- /package/examples/{RBAC → features/rbac}/PermissionExample.tsx +0 -0
- /package/examples/{RBAC → features/rbac}/index.ts +0 -0
- /package/src/utils/{appConfig.ts → app/appConfig.ts} +0 -0
- /package/src/utils/{appNameResolver.simple.test.ts → app/appNameResolver.simple.test.ts} +0 -0
- /package/src/utils/{audit.ts → audit/audit.ts} +0 -0
- /package/src/utils/{organisationContext.test.ts → context/organisationContext.test.ts} +0 -0
- /package/src/utils/{cn.ts → core/cn.ts} +0 -0
- /package/src/utils/{debugLogger.ts → core/debugLogger.ts} +0 -0
- /package/src/utils/{dynamicUtils.ts → dynamic/dynamicUtils.ts} +0 -0
- /package/src/utils/{formatDate.test.ts → formatting/formatDate.test.ts} +0 -0
- /package/src/utils/{formatting.ts → formatting/formatting.ts} +0 -0
- /package/src/utils/{bundleAnalysis.ts → performance/bundleAnalysis.ts} +0 -0
- /package/src/utils/{performanceBenchmark.ts → performance/performanceBenchmark.ts} +0 -0
- /package/src/utils/{performanceBudgets.ts → performance/performanceBudgets.ts} +0 -0
- /package/src/utils/{permissionTypes.ts → permissions/permissionTypes.ts} +0 -0
- /package/src/utils/{permissionUtils.test.ts → permissions/permissionUtils.test.ts} +0 -0
- /package/src/utils/{permissionUtils.ts → permissions/permissionUtils.ts} +0 -0
- /package/src/utils/{auth-utils.ts → security/auth-utils.ts} +0 -0
- /package/src/utils/{secureDataAccess.test.ts → security/secureDataAccess.test.ts} +0 -0
- /package/src/utils/{secureDataAccess.ts → security/secureDataAccess.ts} +0 -0
- /package/src/utils/{secureStorage.ts → security/secureStorage.ts} +0 -0
- /package/src/utils/{securityMonitor.ts → security/securityMonitor.ts} +0 -0
- /package/src/{validation → utils/validation}/common.ts +0 -0
- /package/src/{validation → utils/validation}/passwordSchema.ts +0 -0
- /package/src/{validation → utils/validation}/user.ts +0 -0
- /package/src/utils/{validation.ts → validation/validation.ts} +0 -0
|
@@ -0,0 +1,670 @@
|
|
|
1
|
+
import {
|
|
2
|
+
init_secureStorage,
|
|
3
|
+
secureStorage
|
|
4
|
+
} from "./chunk-444EZN6N.js";
|
|
5
|
+
import {
|
|
6
|
+
createLogger,
|
|
7
|
+
init_logger
|
|
8
|
+
} from "./chunk-XDNLUEXI.js";
|
|
9
|
+
|
|
10
|
+
// src/utils/validation/validation.ts
|
|
11
|
+
function isValidEmail(email) {
|
|
12
|
+
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
13
|
+
return emailPattern.test(email);
|
|
14
|
+
}
|
|
15
|
+
function isEmpty(value) {
|
|
16
|
+
return value === null || value === void 0 || value.trim() === "";
|
|
17
|
+
}
|
|
18
|
+
function isStrongPassword(password) {
|
|
19
|
+
const passwordPattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/;
|
|
20
|
+
return passwordPattern.test(password);
|
|
21
|
+
}
|
|
22
|
+
function isValidUrl(url) {
|
|
23
|
+
try {
|
|
24
|
+
new URL(url);
|
|
25
|
+
return true;
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function isValidDate(dateStr) {
|
|
31
|
+
const date = new Date(dateStr);
|
|
32
|
+
return !isNaN(date.getTime());
|
|
33
|
+
}
|
|
34
|
+
function isWithinRange(value, min, max) {
|
|
35
|
+
return value >= min && value <= max;
|
|
36
|
+
}
|
|
37
|
+
function matchesPattern(value, pattern) {
|
|
38
|
+
return pattern.test(value);
|
|
39
|
+
}
|
|
40
|
+
function deepMerge(target, source) {
|
|
41
|
+
const output = { ...target };
|
|
42
|
+
if (isObject(target) && isObject(source)) {
|
|
43
|
+
Object.keys(source).forEach((key) => {
|
|
44
|
+
if (isObject(source[key])) {
|
|
45
|
+
if (!(key in target)) {
|
|
46
|
+
Object.assign(output, { [key]: source[key] });
|
|
47
|
+
} else {
|
|
48
|
+
const targetKey = key;
|
|
49
|
+
const targetValue = target[targetKey];
|
|
50
|
+
if (isObject(targetValue)) {
|
|
51
|
+
output[targetKey] = deepMerge(
|
|
52
|
+
targetValue,
|
|
53
|
+
source[key]
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
Object.assign(output, { [key]: source[key] });
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return output;
|
|
63
|
+
}
|
|
64
|
+
function isObject(item) {
|
|
65
|
+
return item !== null && typeof item === "object" && !Array.isArray(item);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/utils/validation/sanitization.ts
|
|
69
|
+
import { z } from "zod";
|
|
70
|
+
var DEFAULT_OPTIONS = {
|
|
71
|
+
allowHtml: false,
|
|
72
|
+
allowedTags: [],
|
|
73
|
+
maxLength: 1e3,
|
|
74
|
+
trim: true,
|
|
75
|
+
removeScripts: true,
|
|
76
|
+
removeEvents: true
|
|
77
|
+
};
|
|
78
|
+
function sanitizeUserInput(input, options = {}) {
|
|
79
|
+
if (typeof input !== "string") {
|
|
80
|
+
return "";
|
|
81
|
+
}
|
|
82
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
83
|
+
let sanitized = input;
|
|
84
|
+
if (opts.trim) {
|
|
85
|
+
sanitized = sanitized.trim();
|
|
86
|
+
}
|
|
87
|
+
if (opts.maxLength && sanitized.length > opts.maxLength) {
|
|
88
|
+
sanitized = sanitized.substring(0, opts.maxLength);
|
|
89
|
+
}
|
|
90
|
+
if (!opts.allowHtml) {
|
|
91
|
+
sanitized = sanitized.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/\//g, "/");
|
|
92
|
+
} else if (opts.allowedTags && opts.allowedTags.length > 0) {
|
|
93
|
+
const allowedTagsRegex = new RegExp(`<(?!/?(?:${opts.allowedTags.join("|")})s*/?>)[^>]+>`, "gi");
|
|
94
|
+
sanitized = sanitized.replace(allowedTagsRegex, "");
|
|
95
|
+
}
|
|
96
|
+
if (opts.removeScripts) {
|
|
97
|
+
sanitized = sanitized.replace(/<script[^>]*>.*?<\/script>/gi, "").replace(/javascript:/gi, "").replace(/vbscript:/gi, "").replace(/data:/gi, "");
|
|
98
|
+
}
|
|
99
|
+
if (opts.removeEvents) {
|
|
100
|
+
sanitized = sanitized.replace(/on\w+\s*=/gi, "");
|
|
101
|
+
}
|
|
102
|
+
return sanitized;
|
|
103
|
+
}
|
|
104
|
+
function sanitizeEmail(email) {
|
|
105
|
+
if (typeof email !== "string") {
|
|
106
|
+
return "";
|
|
107
|
+
}
|
|
108
|
+
return email.trim().toLowerCase().replace(/[^\w@.-]/g, "");
|
|
109
|
+
}
|
|
110
|
+
function sanitizeFormData(data, schema, sanitizationRules) {
|
|
111
|
+
try {
|
|
112
|
+
if (sanitizationRules && typeof data === "object" && data !== null) {
|
|
113
|
+
const sanitizedData = { ...data };
|
|
114
|
+
Object.entries(sanitizationRules).forEach(([field, options]) => {
|
|
115
|
+
if (typeof sanitizedData[field] === "string") {
|
|
116
|
+
sanitizedData[field] = sanitizeUserInput(sanitizedData[field], options);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
data = sanitizedData;
|
|
120
|
+
}
|
|
121
|
+
const result = schema.parse(data);
|
|
122
|
+
return { success: true, data: result };
|
|
123
|
+
} catch (error) {
|
|
124
|
+
if (error instanceof z.ZodError) {
|
|
125
|
+
return {
|
|
126
|
+
success: false,
|
|
127
|
+
error: error.errors.map((e) => e.message).join(", ")
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
success: false,
|
|
132
|
+
error: "Validation failed"
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
var secureEmailSchema = z.string().min(1, "Email is required").email("Invalid email format").max(254, "Email too long").refine(
|
|
137
|
+
(email) => {
|
|
138
|
+
if (!email || typeof email !== "string") return false;
|
|
139
|
+
const domain = email.split("@")[1];
|
|
140
|
+
return domain && domain.includes(".") && domain.length > 3;
|
|
141
|
+
},
|
|
142
|
+
"Invalid email domain"
|
|
143
|
+
).transform((email) => sanitizeEmail(email));
|
|
144
|
+
var emailSchema = z.string().min(1, "Email is required").email("Invalid email format");
|
|
145
|
+
var nameSchema = z.string().min(1, "Name is required").max(100, "Name too long").regex(/^[a-zA-Z\s'-]+$/, "Name contains invalid characters");
|
|
146
|
+
var phoneSchema = z.string().regex(/^[\+]?[1-9][\d]{0,15}$/, "Invalid phone number format");
|
|
147
|
+
var urlSchema = z.string().url("Invalid URL format");
|
|
148
|
+
var dateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Invalid date format (YYYY-MM-DD)");
|
|
149
|
+
var secureLoginSchema = z.object({
|
|
150
|
+
email: secureEmailSchema,
|
|
151
|
+
password: z.string().min(1, "Password is required")
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// src/utils/validation/validationUtils.ts
|
|
155
|
+
import { z as z2 } from "zod";
|
|
156
|
+
init_logger();
|
|
157
|
+
var log = createLogger("ValidationUtils");
|
|
158
|
+
function validateUserInput(schema, data, sanitizationRules) {
|
|
159
|
+
return sanitizeFormData(data, schema, sanitizationRules);
|
|
160
|
+
}
|
|
161
|
+
function sanitizeUserInput_deprecated(input) {
|
|
162
|
+
log.warn("sanitizeUserInput is deprecated. Use sanitizeUserInput from lib/sanitization instead.");
|
|
163
|
+
return sanitizeUserInput(input);
|
|
164
|
+
}
|
|
165
|
+
var emailSchema2 = z2.string().transform((email) => email.toLowerCase().trim()).pipe(z2.string().min(1, "Email is required").email("Invalid email format").max(254, "Email too long"));
|
|
166
|
+
var passwordSchema = z2.string().min(8, "Password must be at least 8 characters").max(128, "Password too long").regex(/[A-Z]/, "Password must contain at least one uppercase letter").regex(/[a-z]/, "Password must contain at least one lowercase letter").regex(/[0-9]/, "Password must contain at least one number").regex(/[^A-Za-z0-9]/, "Password must contain at least one special character");
|
|
167
|
+
var usernameSchema = z2.string().transform((username) => username.toLowerCase().trim()).pipe(z2.string().min(3, "Username must be at least 3 characters").max(30, "Username too long").regex(/^[a-zA-Z0-9_-]+$/, "Username can only contain letters, numbers, hyphens, and underscores"));
|
|
168
|
+
var nameSchema2 = z2.string().min(1, "Name is required").max(100, "Name too long").refine((name) => {
|
|
169
|
+
const dangerousPatterns = [
|
|
170
|
+
/<script/i,
|
|
171
|
+
/<img/i,
|
|
172
|
+
/on\w+\s*=/i,
|
|
173
|
+
/javascript:/i,
|
|
174
|
+
/data:/i,
|
|
175
|
+
/vbscript:/i
|
|
176
|
+
];
|
|
177
|
+
return !dangerousPatterns.some((pattern) => pattern.test(name));
|
|
178
|
+
}, "Name contains invalid characters").transform((name) => sanitizeUserInput(name, {
|
|
179
|
+
allowHtml: false,
|
|
180
|
+
maxLength: 100,
|
|
181
|
+
trim: true
|
|
182
|
+
}));
|
|
183
|
+
var phoneSchema2 = z2.string().min(10, "Phone number must be at least 10 digits").max(20, "Phone number too long").regex(/^[\+]?[0-9\s\-\(\)\.]+$/, "Invalid phone number format").refine((phone) => {
|
|
184
|
+
const digitsOnly = phone.replace(/\D/g, "");
|
|
185
|
+
return digitsOnly.length >= 10 && digitsOnly.length <= 15;
|
|
186
|
+
}, "Phone number must be between 10 and 15 digits");
|
|
187
|
+
var urlSchema2 = z2.string().min(1, "URL is required").max(2048, "URL too long").refine((url) => {
|
|
188
|
+
try {
|
|
189
|
+
const parsed = new URL(url);
|
|
190
|
+
return ["http:", "https:"].includes(parsed.protocol);
|
|
191
|
+
} catch {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}, "Invalid URL format").refine((url) => {
|
|
195
|
+
const dangerousPatterns = [
|
|
196
|
+
/javascript:/i,
|
|
197
|
+
/data:/i,
|
|
198
|
+
/vbscript:/i,
|
|
199
|
+
/file:/i,
|
|
200
|
+
/mailto:/i
|
|
201
|
+
];
|
|
202
|
+
return !dangerousPatterns.some((pattern) => pattern.test(url));
|
|
203
|
+
}, "URL contains invalid protocol");
|
|
204
|
+
|
|
205
|
+
// src/utils/validation/common.ts
|
|
206
|
+
import { z as z3 } from "zod";
|
|
207
|
+
var emailSchema3 = z3.string().min(1, "Email is required").email("Invalid email format").max(254, "Email too long");
|
|
208
|
+
var nameSchema3 = z3.string().min(1, "Name is required").max(100, "Name too long").regex(/^[a-zA-Z\s'-]+$/, "Name contains invalid characters");
|
|
209
|
+
var phoneSchema3 = z3.string().regex(/^\+?[\d\s\-\(\)]+$/, "Invalid phone number format").min(10, "Phone number too short").max(20, "Phone number too long");
|
|
210
|
+
var urlSchema3 = z3.string().url("Invalid URL format").max(2048, "URL too long");
|
|
211
|
+
var dateSchema2 = z3.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").refine((date) => {
|
|
212
|
+
const parsed = new Date(date);
|
|
213
|
+
return !isNaN(parsed.getTime());
|
|
214
|
+
}, "Invalid date");
|
|
215
|
+
|
|
216
|
+
// src/utils/validation/csrf.ts
|
|
217
|
+
init_secureStorage();
|
|
218
|
+
var CSRFManager = class {
|
|
219
|
+
constructor() {
|
|
220
|
+
this.tokenCache = /* @__PURE__ */ new Map();
|
|
221
|
+
this.TOKEN_EXPIRY = 30 * 60 * 1e3;
|
|
222
|
+
// 30 minutes
|
|
223
|
+
this.MAX_TOKENS_PER_SESSION = 10;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Generate a new CSRF token for the current session
|
|
227
|
+
*/
|
|
228
|
+
async generateToken(sessionId) {
|
|
229
|
+
try {
|
|
230
|
+
await this.cleanupExpiredTokens();
|
|
231
|
+
const sessionTokens = Array.from(this.tokenCache.values()).filter((data) => data.sessionId === sessionId && !data.used);
|
|
232
|
+
if (sessionTokens.length >= this.MAX_TOKENS_PER_SESSION) {
|
|
233
|
+
const oldest = sessionTokens.sort((a, b) => a.timestamp - b.timestamp)[0];
|
|
234
|
+
this.tokenCache.delete(oldest.token);
|
|
235
|
+
}
|
|
236
|
+
const tokenBytes = new Uint8Array(32);
|
|
237
|
+
crypto.getRandomValues(tokenBytes);
|
|
238
|
+
const token = Array.from(
|
|
239
|
+
tokenBytes,
|
|
240
|
+
(byte) => byte.toString(16).padStart(2, "0")
|
|
241
|
+
).join("");
|
|
242
|
+
const tokenData = {
|
|
243
|
+
token,
|
|
244
|
+
sessionId,
|
|
245
|
+
timestamp: Date.now(),
|
|
246
|
+
used: false
|
|
247
|
+
};
|
|
248
|
+
this.tokenCache.set(token, tokenData);
|
|
249
|
+
await this.persistTokens();
|
|
250
|
+
return token;
|
|
251
|
+
} catch (error) {
|
|
252
|
+
throw new Error("CSRF token generation failed");
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Validate and consume a CSRF token
|
|
257
|
+
*/
|
|
258
|
+
async validateToken(token, sessionId) {
|
|
259
|
+
try {
|
|
260
|
+
if (this.tokenCache.size === 0) {
|
|
261
|
+
await this.loadTokens();
|
|
262
|
+
}
|
|
263
|
+
const tokenData = this.tokenCache.get(token);
|
|
264
|
+
if (!tokenData) {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
if (tokenData.sessionId !== sessionId) {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
if (tokenData.used) {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
if (Date.now() - tokenData.timestamp > this.TOKEN_EXPIRY) {
|
|
274
|
+
this.tokenCache.delete(token);
|
|
275
|
+
await this.persistTokens();
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
tokenData.used = true;
|
|
279
|
+
this.tokenCache.set(token, tokenData);
|
|
280
|
+
await this.persistTokens();
|
|
281
|
+
return true;
|
|
282
|
+
} catch (error) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Get current valid token for session
|
|
288
|
+
*/
|
|
289
|
+
async getCurrentToken(sessionId) {
|
|
290
|
+
if (this.tokenCache.size === 0) {
|
|
291
|
+
await this.loadTokens();
|
|
292
|
+
}
|
|
293
|
+
for (const [token, data] of this.tokenCache.entries()) {
|
|
294
|
+
if (data.sessionId === sessionId && !data.used && Date.now() - data.timestamp < this.TOKEN_EXPIRY) {
|
|
295
|
+
return token;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return await this.generateToken(sessionId);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Clean up expired and used tokens
|
|
302
|
+
*/
|
|
303
|
+
async cleanupExpiredTokens() {
|
|
304
|
+
const now = Date.now();
|
|
305
|
+
const expiredTokens = [];
|
|
306
|
+
for (const [token, data] of this.tokenCache.entries()) {
|
|
307
|
+
if (data.used || now - data.timestamp > this.TOKEN_EXPIRY) {
|
|
308
|
+
expiredTokens.push(token);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
expiredTokens.forEach((token) => this.tokenCache.delete(token));
|
|
312
|
+
if (expiredTokens.length > 0) {
|
|
313
|
+
await this.persistTokens();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Persist tokens to secure storage
|
|
318
|
+
*/
|
|
319
|
+
async persistTokens() {
|
|
320
|
+
try {
|
|
321
|
+
const tokensArray = Array.from(this.tokenCache.entries());
|
|
322
|
+
await secureStorage.setItem(
|
|
323
|
+
"csrf_tokens",
|
|
324
|
+
JSON.stringify(tokensArray),
|
|
325
|
+
{ encrypt: true, expiry: this.TOKEN_EXPIRY }
|
|
326
|
+
);
|
|
327
|
+
} catch (error) {
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Load tokens from secure storage
|
|
332
|
+
*/
|
|
333
|
+
async loadTokens() {
|
|
334
|
+
try {
|
|
335
|
+
const tokensData = await secureStorage.getItem("csrf_tokens");
|
|
336
|
+
if (tokensData) {
|
|
337
|
+
const tokensArray = JSON.parse(tokensData);
|
|
338
|
+
this.tokenCache = new Map(tokensArray);
|
|
339
|
+
await this.cleanupExpiredTokens();
|
|
340
|
+
}
|
|
341
|
+
} catch (error) {
|
|
342
|
+
this.tokenCache.clear();
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Clear all tokens for session
|
|
347
|
+
*/
|
|
348
|
+
async clearSession(sessionId) {
|
|
349
|
+
const tokensToRemove = [];
|
|
350
|
+
for (const [token, data] of this.tokenCache.entries()) {
|
|
351
|
+
if (data.sessionId === sessionId) {
|
|
352
|
+
tokensToRemove.push(token);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
tokensToRemove.forEach((token) => this.tokenCache.delete(token));
|
|
356
|
+
await this.persistTokens();
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
var csrfManager = new CSRFManager();
|
|
360
|
+
async function generateCSRFToken(sessionId) {
|
|
361
|
+
return csrfManager.generateToken(sessionId);
|
|
362
|
+
}
|
|
363
|
+
async function validateCSRFToken(token, sessionId) {
|
|
364
|
+
return csrfManager.validateToken(token, sessionId);
|
|
365
|
+
}
|
|
366
|
+
async function getCSRFToken(sessionId) {
|
|
367
|
+
return csrfManager.getCurrentToken(sessionId);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// src/utils/validation/sqlInjectionProtection.ts
|
|
371
|
+
import { z as z4 } from "zod";
|
|
372
|
+
var SQL_INJECTION_PATTERNS = [
|
|
373
|
+
/(\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC|EXECUTE|UNION|SCRIPT|JAVASCRIPT)\b)/i,
|
|
374
|
+
/(\'|(\\\')|(\'\')|(\"|(\\\")|(\\")))|(\\x)|(\\u)/i,
|
|
375
|
+
/((%27)|(')|(%6F)|o|(%4F)|(%72)|r|(%52))/i,
|
|
376
|
+
// '|%27|' OR
|
|
377
|
+
/((%27)|(')|(%55)|u|(%55)|(%4E)|n|(%4E)|(%49)|i|(%49)|(%4F)|o|(%4F)|(%4E)|n|(%4E))/i,
|
|
378
|
+
// '|%27|' UNION
|
|
379
|
+
/((%3D)|(=))[^\n]*((%27)|(')|((\\x27))|((\\x2D))|((\\x23)))/i,
|
|
380
|
+
/(w*((%27)|(')|(%6F)|o|(%4F)|(%72)|r|(%52)))/i,
|
|
381
|
+
/((%27)|(')|(''))+union/i,
|
|
382
|
+
/exec(\+|\s)+(s|x)p\w+/i,
|
|
383
|
+
/\b(and|or)\b.+?(=|<|>|\bin\b|\blike\b)/i,
|
|
384
|
+
/\bunion\b.+?\bselect\b/i,
|
|
385
|
+
/\bdrop\b.+?\btable\b/i,
|
|
386
|
+
/\binsert\b.+?\binto\b/i,
|
|
387
|
+
/\bdelete\b.+?\bfrom\b/i,
|
|
388
|
+
/\bupdate\b.+?\bset\b/i,
|
|
389
|
+
/(;|(\\x3B)).+?(drop|create|alter|exec|execute|insert|update|delete)/i,
|
|
390
|
+
/(%3B|;).+?(%44|%64|d)(%52|%72|r)(%4F|%6F|o)(%50|%70|p)/i
|
|
391
|
+
];
|
|
392
|
+
var DANGEROUS_CHARS = /[';\"\\%]/g;
|
|
393
|
+
var searchQuerySchema = z4.string().max(500, "Search query too long").refine(
|
|
394
|
+
(query) => {
|
|
395
|
+
return !SQL_INJECTION_PATTERNS.some((pattern) => pattern.test(query));
|
|
396
|
+
},
|
|
397
|
+
"Invalid characters detected in search query"
|
|
398
|
+
).transform((query) => sanitizeSearchQuery(query));
|
|
399
|
+
var sqlIdentifierSchema = z4.string().min(1, "Identifier cannot be empty").max(63, "Identifier too long").regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/, "Invalid identifier format").refine(
|
|
400
|
+
(identifier) => {
|
|
401
|
+
const reservedWords = [
|
|
402
|
+
"SELECT",
|
|
403
|
+
"INSERT",
|
|
404
|
+
"UPDATE",
|
|
405
|
+
"DELETE",
|
|
406
|
+
"DROP",
|
|
407
|
+
"CREATE",
|
|
408
|
+
"ALTER",
|
|
409
|
+
"FROM",
|
|
410
|
+
"WHERE",
|
|
411
|
+
"JOIN",
|
|
412
|
+
"UNION",
|
|
413
|
+
"ORDER",
|
|
414
|
+
"GROUP",
|
|
415
|
+
"HAVING"
|
|
416
|
+
];
|
|
417
|
+
return !reservedWords.includes(identifier.toUpperCase());
|
|
418
|
+
},
|
|
419
|
+
"Identifier cannot be a reserved SQL keyword"
|
|
420
|
+
);
|
|
421
|
+
var orderBySchema = z4.string().regex(/^[a-zA-Z_][a-zA-Z0-9_]*(\s+(ASC|DESC|asc|desc))?$/, "Invalid order by format");
|
|
422
|
+
var limitOffsetSchema = z4.number().int("Must be an integer").min(0, "Must be non-negative").max(1e3, "Limit too large");
|
|
423
|
+
function sanitizeSearchQuery(query) {
|
|
424
|
+
return query.replace(DANGEROUS_CHARS, "").replace(/\s+/g, " ").trim().slice(0, 500);
|
|
425
|
+
}
|
|
426
|
+
function escapeLikeQuery(query) {
|
|
427
|
+
return query.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
428
|
+
}
|
|
429
|
+
function sanitizeFilters(filters) {
|
|
430
|
+
const sanitized = {};
|
|
431
|
+
for (const [key, value] of Object.entries(filters)) {
|
|
432
|
+
const keyValidation = sqlIdentifierSchema.safeParse(key);
|
|
433
|
+
if (!keyValidation.success) {
|
|
434
|
+
console.warn(`[SECURITY] Invalid filter key detected and removed: ${key}`);
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
if (typeof value === "string") {
|
|
438
|
+
const valueValidation = searchQuerySchema.safeParse(value);
|
|
439
|
+
if (valueValidation.success) {
|
|
440
|
+
sanitized[key] = valueValidation.data;
|
|
441
|
+
}
|
|
442
|
+
} else if (typeof value === "number") {
|
|
443
|
+
if (Number.isFinite(value)) {
|
|
444
|
+
sanitized[key] = value;
|
|
445
|
+
}
|
|
446
|
+
} else if (typeof value === "boolean") {
|
|
447
|
+
sanitized[key] = value;
|
|
448
|
+
} else if (Array.isArray(value)) {
|
|
449
|
+
const sanitizedArray = value.filter((item) => typeof item === "string" || typeof item === "number").map((item) => typeof item === "string" ? sanitizeSearchQuery(item) : item).slice(0, 100);
|
|
450
|
+
if (sanitizedArray.length > 0) {
|
|
451
|
+
sanitized[key] = sanitizedArray;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return sanitized;
|
|
456
|
+
}
|
|
457
|
+
function buildSafeQueryParams(params) {
|
|
458
|
+
const safe = {};
|
|
459
|
+
if (params.select) {
|
|
460
|
+
const selectFields = params.select.split(",").map((field) => field.trim());
|
|
461
|
+
const validFields = selectFields.filter((field) => {
|
|
462
|
+
return sqlIdentifierSchema.safeParse(field).success;
|
|
463
|
+
});
|
|
464
|
+
if (validFields.length > 0) {
|
|
465
|
+
safe.select = validFields.join(", ");
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (params.filters) {
|
|
469
|
+
safe.filters = sanitizeFilters(params.filters);
|
|
470
|
+
}
|
|
471
|
+
if (params.orderBy) {
|
|
472
|
+
const orderByValidation = orderBySchema.safeParse(params.orderBy);
|
|
473
|
+
if (orderByValidation.success) {
|
|
474
|
+
safe.orderBy = orderByValidation.data;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
if (params.limit !== void 0) {
|
|
478
|
+
const limitValidation = limitOffsetSchema.safeParse(params.limit);
|
|
479
|
+
if (limitValidation.success) {
|
|
480
|
+
safe.limit = limitValidation.data;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (params.offset !== void 0) {
|
|
484
|
+
const offsetValidation = limitOffsetSchema.safeParse(params.offset);
|
|
485
|
+
if (offsetValidation.success) {
|
|
486
|
+
safe.offset = offsetValidation.data;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
if (params.search) {
|
|
490
|
+
const searchValidation = searchQuerySchema.safeParse(params.search);
|
|
491
|
+
if (searchValidation.success) {
|
|
492
|
+
safe.search = searchValidation.data;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
return safe;
|
|
496
|
+
}
|
|
497
|
+
function detectSQLInjection(input) {
|
|
498
|
+
const detectedPatterns = [];
|
|
499
|
+
let maxRisk = "low";
|
|
500
|
+
SQL_INJECTION_PATTERNS.forEach((pattern, index) => {
|
|
501
|
+
if (pattern.test(input)) {
|
|
502
|
+
detectedPatterns.push(`Pattern ${index + 1}`);
|
|
503
|
+
if (index < 3) {
|
|
504
|
+
maxRisk = "critical";
|
|
505
|
+
} else if (index < 7 && maxRisk !== "critical") {
|
|
506
|
+
maxRisk = "high";
|
|
507
|
+
} else if (index < 12 && !["critical", "high"].includes(maxRisk)) {
|
|
508
|
+
maxRisk = "medium";
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
return {
|
|
513
|
+
isSuspicious: detectedPatterns.length > 0,
|
|
514
|
+
patterns: detectedPatterns,
|
|
515
|
+
riskLevel: maxRisk
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// src/utils/validation/passwordSchema.ts
|
|
520
|
+
import { z as z5 } from "zod";
|
|
521
|
+
var COMMON_PASSWORDS = /* @__PURE__ */ new Set([
|
|
522
|
+
"password",
|
|
523
|
+
"123456",
|
|
524
|
+
"123456789",
|
|
525
|
+
"qwerty",
|
|
526
|
+
"abc123",
|
|
527
|
+
"password123",
|
|
528
|
+
"admin",
|
|
529
|
+
"letmein",
|
|
530
|
+
"welcome",
|
|
531
|
+
"monkey",
|
|
532
|
+
"1234567890",
|
|
533
|
+
"password1"
|
|
534
|
+
]);
|
|
535
|
+
var WEAK_PATTERNS = [
|
|
536
|
+
/^(.)\1+$/,
|
|
537
|
+
// All same character
|
|
538
|
+
/^(012|123|234|345|456|567|678|789|890|987|876|765|654|543|432|321|210)+/,
|
|
539
|
+
// Sequential numbers
|
|
540
|
+
/^(abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz)+/i
|
|
541
|
+
// Sequential letters
|
|
542
|
+
];
|
|
543
|
+
var securePasswordSchema = z5.string().min(8, "Password must be at least 8 characters long").max(128, "Password must not exceed 128 characters").refine(
|
|
544
|
+
(password) => /[a-z]/.test(password),
|
|
545
|
+
"Password must contain at least one lowercase letter"
|
|
546
|
+
).refine(
|
|
547
|
+
(password) => /[A-Z]/.test(password),
|
|
548
|
+
"Password must contain at least one uppercase letter"
|
|
549
|
+
).refine(
|
|
550
|
+
(password) => /\d/.test(password),
|
|
551
|
+
"Password must contain at least one number"
|
|
552
|
+
).refine(
|
|
553
|
+
(password) => /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password),
|
|
554
|
+
"Password must contain at least one special character"
|
|
555
|
+
).refine(
|
|
556
|
+
(password) => !COMMON_PASSWORDS.has(password.toLowerCase()),
|
|
557
|
+
"Password is too common. Please choose a stronger password"
|
|
558
|
+
).refine(
|
|
559
|
+
(password) => !WEAK_PATTERNS.some((pattern) => pattern.test(password)),
|
|
560
|
+
"Password contains weak patterns. Please choose a more complex password"
|
|
561
|
+
).refine(
|
|
562
|
+
(password) => {
|
|
563
|
+
const keyboardPatterns = ["qwerty", "asdfgh", "zxcvbn", "1234567890"];
|
|
564
|
+
return !keyboardPatterns.some(
|
|
565
|
+
(pattern) => password.toLowerCase().includes(pattern)
|
|
566
|
+
);
|
|
567
|
+
},
|
|
568
|
+
"Password contains keyboard patterns. Please choose a more secure password"
|
|
569
|
+
);
|
|
570
|
+
var passwordSchema2 = z5.string().min(6, "Password must be at least 6 characters long").max(128, "Password must not exceed 128 characters");
|
|
571
|
+
function calculatePasswordStrength(password) {
|
|
572
|
+
let score = 0;
|
|
573
|
+
const feedback = [];
|
|
574
|
+
if (password.length >= 8) score += 20;
|
|
575
|
+
else if (password.length >= 6) score += 10;
|
|
576
|
+
else feedback.push("Use at least 8 characters");
|
|
577
|
+
if (/[a-z]/.test(password)) score += 15;
|
|
578
|
+
else feedback.push("Add lowercase letters");
|
|
579
|
+
if (/[A-Z]/.test(password)) score += 15;
|
|
580
|
+
else feedback.push("Add uppercase letters");
|
|
581
|
+
if (/\d/.test(password)) score += 15;
|
|
582
|
+
else feedback.push("Add numbers");
|
|
583
|
+
if (/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password)) score += 15;
|
|
584
|
+
else feedback.push("Add special characters");
|
|
585
|
+
if (password.length >= 12) score += 10;
|
|
586
|
+
if (/[^a-zA-Z0-9]/.test(password)) score += 10;
|
|
587
|
+
if (COMMON_PASSWORDS.has(password.toLowerCase())) {
|
|
588
|
+
score -= 30;
|
|
589
|
+
feedback.push("Avoid common passwords");
|
|
590
|
+
}
|
|
591
|
+
if (WEAK_PATTERNS.some((pattern) => pattern.test(password))) {
|
|
592
|
+
score -= 20;
|
|
593
|
+
feedback.push("Avoid predictable patterns");
|
|
594
|
+
}
|
|
595
|
+
let level;
|
|
596
|
+
if (score < 30) level = "very-weak";
|
|
597
|
+
else if (score < 50) level = "weak";
|
|
598
|
+
else if (score < 70) level = "fair";
|
|
599
|
+
else if (score < 90) level = "good";
|
|
600
|
+
else level = "strong";
|
|
601
|
+
return { score: Math.max(0, Math.min(100, score)), feedback, level };
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/utils/validation/user.ts
|
|
605
|
+
import { z as z6 } from "zod";
|
|
606
|
+
var userProfileSchema = z6.object({
|
|
607
|
+
name: nameSchema3,
|
|
608
|
+
email: emailSchema3,
|
|
609
|
+
phone: z6.string().optional(),
|
|
610
|
+
website: z6.string().url().optional(),
|
|
611
|
+
bio: z6.string().max(500).optional()
|
|
612
|
+
});
|
|
613
|
+
var userSettingsSchema = z6.object({
|
|
614
|
+
notifications: z6.object({
|
|
615
|
+
email: z6.boolean(),
|
|
616
|
+
push: z6.boolean()
|
|
617
|
+
}),
|
|
618
|
+
language: z6.string()
|
|
619
|
+
});
|
|
620
|
+
var userPreferencesSchema = z6.object({
|
|
621
|
+
displayName: nameSchema3,
|
|
622
|
+
timezone: z6.string(),
|
|
623
|
+
dateFormat: z6.string(),
|
|
624
|
+
currency: z6.string()
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
export {
|
|
628
|
+
isValidEmail,
|
|
629
|
+
isEmpty,
|
|
630
|
+
isStrongPassword,
|
|
631
|
+
isValidUrl,
|
|
632
|
+
isValidDate,
|
|
633
|
+
isWithinRange,
|
|
634
|
+
matchesPattern,
|
|
635
|
+
deepMerge,
|
|
636
|
+
isObject,
|
|
637
|
+
sanitizeUserInput,
|
|
638
|
+
sanitizeFormData,
|
|
639
|
+
validateUserInput,
|
|
640
|
+
sanitizeUserInput_deprecated,
|
|
641
|
+
emailSchema2 as emailSchema,
|
|
642
|
+
passwordSchema,
|
|
643
|
+
usernameSchema,
|
|
644
|
+
nameSchema2 as nameSchema,
|
|
645
|
+
phoneSchema2 as phoneSchema,
|
|
646
|
+
urlSchema2 as urlSchema,
|
|
647
|
+
emailSchema3 as emailSchema2,
|
|
648
|
+
nameSchema3 as nameSchema2,
|
|
649
|
+
phoneSchema3 as phoneSchema2,
|
|
650
|
+
urlSchema3 as urlSchema2,
|
|
651
|
+
dateSchema2 as dateSchema,
|
|
652
|
+
csrfManager,
|
|
653
|
+
generateCSRFToken,
|
|
654
|
+
validateCSRFToken,
|
|
655
|
+
getCSRFToken,
|
|
656
|
+
searchQuerySchema,
|
|
657
|
+
sqlIdentifierSchema,
|
|
658
|
+
orderBySchema,
|
|
659
|
+
limitOffsetSchema,
|
|
660
|
+
sanitizeSearchQuery,
|
|
661
|
+
escapeLikeQuery,
|
|
662
|
+
sanitizeFilters,
|
|
663
|
+
buildSafeQueryParams,
|
|
664
|
+
detectSQLInjection,
|
|
665
|
+
passwordSchema2,
|
|
666
|
+
calculatePasswordStrength,
|
|
667
|
+
userSettingsSchema,
|
|
668
|
+
userPreferencesSchema
|
|
669
|
+
};
|
|
670
|
+
//# sourceMappingURL=chunk-APIBCTL2.js.map
|