@jmruthers/pace-core 0.5.121 → 0.5.123

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.
Files changed (254) hide show
  1. package/dist/{AuthService-D4646R4b.d.ts → AuthService-DYuQPJj6.d.ts} +0 -9
  2. package/dist/{DataTable-DGZDJUYM.js → DataTable-WTS4IRF2.js} +7 -8
  3. package/dist/{PublicLoadingSpinner-DgDWTFqn.d.ts → PublicLoadingSpinner-CaoRbHvJ.d.ts} +30 -4
  4. package/dist/{UnifiedAuthProvider-UACKFATV.js → UnifiedAuthProvider-6C47WIML.js} +3 -4
  5. package/dist/{chunk-D6BOFXYR.js → chunk-35ZDPMBM.js} +3 -3
  6. package/dist/{chunk-CGURJ27Z.js → chunk-4MXVZVNS.js} +2 -2
  7. package/dist/{chunk-ZYJ6O5CA.js → chunk-C43QIDN3.js} +2 -2
  8. package/dist/{chunk-VKOCWWVY.js → chunk-CX5M4ZAG.js} +1 -6
  9. package/dist/{chunk-VKOCWWVY.js 3.map → chunk-CX5M4ZAG.js.map} +1 -1
  10. package/dist/{chunk-HFBOFZ3Z.js → chunk-DHMFMXFV.js} +258 -243
  11. package/dist/chunk-DHMFMXFV.js.map +1 -0
  12. package/dist/{chunk-RIEJGKD3.js → chunk-ESJTIADP.js} +15 -6
  13. package/dist/{chunk-RIEJGKD3.js.map → chunk-ESJTIADP.js.map} +1 -1
  14. package/dist/{chunk-SMJZMKYN.js → chunk-GEVIB2UB.js} +43 -10
  15. package/dist/chunk-GEVIB2UB.js.map +1 -0
  16. package/dist/{chunk-TDNI6ZWL.js → chunk-IJOZZOGT.js} +7 -7
  17. package/dist/chunk-IJOZZOGT.js.map +1 -0
  18. package/dist/{chunk-GZRXOUBE.js → chunk-M6DDYFUD.js} +2 -2
  19. package/dist/chunk-M6DDYFUD.js.map +1 -0
  20. package/dist/{chunk-B4GZ2BXO.js → chunk-NZGLXZGP.js} +3 -3
  21. package/dist/{chunk-NZ32EONV.js → chunk-QWNJCQXZ.js} +2 -2
  22. package/dist/{chunk-FKFHZUGF.js → chunk-XN6GWKMV.js} +43 -56
  23. package/dist/chunk-XN6GWKMV.js.map +1 -0
  24. package/dist/{chunk-BHWIUEYH.js → chunk-ZBLK676C.js} +1 -61
  25. package/dist/chunk-ZBLK676C.js.map +1 -0
  26. package/dist/{chunk-QPI2CCBA.js → chunk-ZPJMYGEP.js} +149 -96
  27. package/dist/chunk-ZPJMYGEP.js.map +1 -0
  28. package/dist/components.d.ts +1 -1
  29. package/dist/components.js +11 -11
  30. package/dist/{formatting-B1jSqgl-.d.ts → formatting-DFcCxUEk.d.ts} +1 -1
  31. package/dist/hooks.d.ts +1 -1
  32. package/dist/hooks.js +9 -8
  33. package/dist/hooks.js.map +1 -1
  34. package/dist/index.d.ts +6 -6
  35. package/dist/index.js +19 -17
  36. package/dist/index.js.map +1 -1
  37. package/dist/providers.d.ts +2 -2
  38. package/dist/providers.js +2 -3
  39. package/dist/rbac/index.js +7 -8
  40. package/dist/styles/index.d.ts +1 -1
  41. package/dist/styles/index.js +5 -3
  42. package/dist/theming/runtime.d.ts +73 -1
  43. package/dist/theming/runtime.js +5 -5
  44. package/dist/{usePublicRouteParams-BdF8bZgs.d.ts → usePublicRouteParams-Dyt1tzI9.d.ts} +60 -8
  45. package/dist/utils.d.ts +1 -1
  46. package/dist/utils.js +5 -5
  47. package/docs/api/classes/ColumnFactory.md +1 -1
  48. package/docs/api/classes/ErrorBoundary.md +1 -1
  49. package/docs/api/classes/InvalidScopeError.md +1 -1
  50. package/docs/api/classes/MissingUserContextError.md +1 -1
  51. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  52. package/docs/api/classes/PermissionDeniedError.md +1 -1
  53. package/docs/api/classes/PublicErrorBoundary.md +6 -6
  54. package/docs/api/classes/RBACAuditManager.md +1 -1
  55. package/docs/api/classes/RBACCache.md +1 -1
  56. package/docs/api/classes/RBACEngine.md +1 -1
  57. package/docs/api/classes/RBACError.md +1 -1
  58. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  59. package/docs/api/classes/SecureSupabaseClient.md +6 -6
  60. package/docs/api/classes/StorageUtils.md +1 -1
  61. package/docs/api/enums/FileCategory.md +1 -1
  62. package/docs/api/interfaces/AggregateConfig.md +1 -1
  63. package/docs/api/interfaces/ButtonProps.md +1 -1
  64. package/docs/api/interfaces/CardProps.md +1 -1
  65. package/docs/api/interfaces/ColorPalette.md +1 -1
  66. package/docs/api/interfaces/ColorShade.md +1 -1
  67. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  68. package/docs/api/interfaces/DataRecord.md +1 -1
  69. package/docs/api/interfaces/DataTableAction.md +1 -1
  70. package/docs/api/interfaces/DataTableColumn.md +1 -1
  71. package/docs/api/interfaces/DataTableProps.md +1 -1
  72. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  73. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  74. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  75. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  76. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  77. package/docs/api/interfaces/FileMetadata.md +1 -1
  78. package/docs/api/interfaces/FileReference.md +1 -1
  79. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  80. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  81. package/docs/api/interfaces/FileUploadProps.md +1 -1
  82. package/docs/api/interfaces/FooterProps.md +1 -1
  83. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  84. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  85. package/docs/api/interfaces/InputProps.md +1 -1
  86. package/docs/api/interfaces/LabelProps.md +1 -1
  87. package/docs/api/interfaces/LoginFormProps.md +1 -1
  88. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  89. package/docs/api/interfaces/NavigationContextType.md +1 -1
  90. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  91. package/docs/api/interfaces/NavigationItem.md +1 -1
  92. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  93. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  94. package/docs/api/interfaces/Organisation.md +1 -1
  95. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  96. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  97. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  98. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  99. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  100. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  101. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  102. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  103. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  104. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  105. package/docs/api/interfaces/PaletteData.md +1 -1
  106. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  107. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  108. package/docs/api/interfaces/PublicErrorBoundaryProps.md +7 -7
  109. package/docs/api/interfaces/PublicErrorBoundaryState.md +5 -5
  110. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +7 -7
  111. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  112. package/docs/api/interfaces/PublicPageHeaderProps.md +51 -12
  113. package/docs/api/interfaces/PublicPageLayoutProps.md +72 -12
  114. package/docs/api/interfaces/RBACConfig.md +1 -1
  115. package/docs/api/interfaces/RBACLogger.md +1 -1
  116. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  117. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  118. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  119. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  120. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  121. package/docs/api/interfaces/RouteConfig.md +1 -1
  122. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  123. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  124. package/docs/api/interfaces/StorageConfig.md +1 -1
  125. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  126. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  127. package/docs/api/interfaces/StorageListOptions.md +1 -1
  128. package/docs/api/interfaces/StorageListResult.md +1 -1
  129. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  130. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  131. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  132. package/docs/api/interfaces/StyleImport.md +1 -1
  133. package/docs/api/interfaces/SwitchProps.md +1 -1
  134. package/docs/api/interfaces/ToastActionElement.md +1 -1
  135. package/docs/api/interfaces/ToastProps.md +1 -1
  136. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  137. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  138. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  139. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  140. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  141. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  142. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  143. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  144. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  145. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  146. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  147. package/docs/api/interfaces/UserEventAccess.md +1 -1
  148. package/docs/api/interfaces/UserMenuProps.md +1 -1
  149. package/docs/api/interfaces/UserProfile.md +1 -1
  150. package/docs/api/modules.md +140 -30
  151. package/docs/best-practices/README.md +1 -1
  152. package/docs/implementation-guides/datatable-filtering.md +313 -0
  153. package/docs/implementation-guides/datatable-rbac-usage.md +317 -0
  154. package/docs/implementation-guides/hierarchical-datatable.md +850 -0
  155. package/docs/implementation-guides/large-datasets.md +281 -0
  156. package/docs/implementation-guides/performance.md +403 -0
  157. package/docs/implementation-guides/public-pages.md +4 -4
  158. package/docs/migration/quick-migration-guide.md +320 -0
  159. package/docs/rbac/quick-start.md +16 -16
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +1 -1
  162. package/docs/troubleshooting/debugging.md +1117 -0
  163. package/docs/troubleshooting/migration.md +918 -0
  164. package/examples/public-pages/CorrectPublicPageImplementation.tsx +30 -30
  165. package/examples/public-pages/PublicEventPage.tsx +41 -41
  166. package/examples/public-pages/PublicPageApp.tsx +33 -33
  167. package/examples/public-pages/PublicPageUsageExample.tsx +30 -30
  168. package/package.json +4 -4
  169. package/src/__tests__/hooks/usePermissions.test.ts +265 -0
  170. package/src/components/DataTable/DataTable.test.tsx +9 -38
  171. package/src/components/DataTable/DataTable.tsx +0 -7
  172. package/src/components/DataTable/components/DataTableCore.tsx +66 -136
  173. package/src/components/DataTable/components/DataTableModals.tsx +25 -22
  174. package/src/components/DataTable/components/EditableRow.tsx +118 -42
  175. package/src/components/DataTable/components/UnifiedTableBody.tsx +129 -76
  176. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +33 -14
  177. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +17 -5
  178. package/src/components/DataTable/utils/exportUtils.ts +3 -2
  179. package/src/components/Dialog/Dialog.tsx +1 -1
  180. package/src/components/Dialog/README.md +24 -24
  181. package/src/components/Dialog/examples/BasicHtmlTest.tsx +2 -2
  182. package/src/components/Dialog/examples/DebugHtmlExample.tsx +6 -6
  183. package/src/components/Dialog/examples/HtmlDialogExample.tsx +2 -2
  184. package/src/components/Dialog/examples/SimpleHtmlTest.tsx +3 -3
  185. package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +4 -4
  186. package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -1
  187. package/src/components/PublicLayout/EventLogo.tsx +175 -0
  188. package/src/components/PublicLayout/PublicErrorBoundary.tsx +22 -18
  189. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +22 -14
  190. package/src/components/PublicLayout/PublicPageHeader.tsx +133 -40
  191. package/src/components/PublicLayout/PublicPageLayout.tsx +75 -72
  192. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +1 -1
  193. package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +8 -8
  194. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +23 -16
  195. package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +86 -14
  196. package/src/examples/CorrectPublicPageImplementation.tsx +30 -30
  197. package/src/examples/PublicEventPage.tsx +41 -41
  198. package/src/examples/PublicPageApp.tsx +33 -33
  199. package/src/examples/PublicPageUsageExample.tsx +30 -30
  200. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
  201. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +10 -3
  202. package/src/hooks/index.ts +1 -1
  203. package/src/hooks/public/usePublicEventLogo.ts +285 -0
  204. package/src/hooks/public/usePublicRouteParams.ts +21 -4
  205. package/src/hooks/useEventTheme.test.ts +119 -43
  206. package/src/hooks/useEventTheme.ts +84 -55
  207. package/src/index.ts +3 -1
  208. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +630 -0
  209. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
  210. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
  211. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +496 -0
  212. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
  213. package/src/rbac/secureClient.ts +4 -2
  214. package/src/services/EventService.ts +0 -66
  215. package/src/services/__tests__/EventService.eventColours.test.ts +44 -40
  216. package/src/styles/index.ts +1 -1
  217. package/src/theming/__tests__/parseEventColours.test.ts +209 -0
  218. package/src/theming/parseEventColours.ts +123 -0
  219. package/src/theming/runtime.ts +3 -0
  220. package/src/types/__tests__/file-reference.test.ts +447 -0
  221. package/src/utils/formatDate.test.ts +11 -11
  222. package/src/utils/formatting.ts +3 -2
  223. package/dist/chunk-BDZUMRBD.js 3.map +0 -1
  224. package/dist/chunk-BHWIUEYH.js.map +0 -1
  225. package/dist/chunk-CGURJ27Z.js.map +0 -1
  226. package/dist/chunk-FKFHZUGF.js.map +0 -1
  227. package/dist/chunk-GKHF54DI 2.js +0 -619
  228. package/dist/chunk-GKHF54DI.js 2.map +0 -1
  229. package/dist/chunk-GZRXOUBE.js.map +0 -1
  230. package/dist/chunk-HFBOFZ3Z.js.map +0 -1
  231. package/dist/chunk-NZ32EONV.js.map +0 -1
  232. package/dist/chunk-O3NWNXDY 2.js +0 -76
  233. package/dist/chunk-QPI2CCBA.js.map +0 -1
  234. package/dist/chunk-SMJZMKYN.js.map +0 -1
  235. package/dist/chunk-TDNI6ZWL.js 2.map +0 -1
  236. package/dist/chunk-TDNI6ZWL.js.map +0 -1
  237. package/dist/chunk-VKOCWWVY.js.map +0 -1
  238. package/dist/chunk-WP5I5GLN 2.js +0 -1564
  239. package/dist/index 3.js +0 -856
  240. package/dist/providers 3.js +0 -38
  241. package/dist/providers.js 3.map +0 -1
  242. package/dist/types 3.js +0 -128
  243. package/dist/types.js 3.map +0 -1
  244. package/dist/useInactivityTracker-MRUU55XI.js 3.map +0 -1
  245. package/dist/utils.js 3.map +0 -1
  246. package/dist/validation 3.js +0 -479
  247. package/src/styles/semantic.css +0 -24
  248. /package/dist/{DataTable-DGZDJUYM.js.map → DataTable-WTS4IRF2.js.map} +0 -0
  249. /package/dist/{UnifiedAuthProvider-UACKFATV.js.map → UnifiedAuthProvider-6C47WIML.js.map} +0 -0
  250. /package/dist/{chunk-D6BOFXYR.js.map → chunk-35ZDPMBM.js.map} +0 -0
  251. /package/dist/{chunk-CGURJ27Z.js 2.map → chunk-4MXVZVNS.js.map} +0 -0
  252. /package/dist/{chunk-ZYJ6O5CA.js.map → chunk-C43QIDN3.js.map} +0 -0
  253. /package/dist/{chunk-B4GZ2BXO.js.map → chunk-NZGLXZGP.js.map} +0 -0
  254. /package/dist/{chunk-NZ32EONV.js 2.map → chunk-QWNJCQXZ.js.map} +0 -0
@@ -1,479 +0,0 @@
1
- import {
2
- changePasswordSchema,
3
- combineSchemas,
4
- contactFormSchema,
5
- dateSchema,
6
- emailSchema,
7
- loginSchema,
8
- nameSchema,
9
- passwordResetSchema,
10
- passwordSchema,
11
- phoneSchema,
12
- pickSchema,
13
- registrationSchema,
14
- secureLoginSchema,
15
- securePasswordSchema,
16
- urlSchema,
17
- userProfileSchema
18
- } from "./chunk-24MKLB7U.js";
19
- import {
20
- init_secureStorage,
21
- secureStorage
22
- } from "./chunk-UJI6WSMD.js";
23
- import "./chunk-PLDDJCW6.js";
24
-
25
- // src/validation/sanitization.ts
26
- import { z } from "zod";
27
- var secureEmailSchema = z.string().min(1, "Email is required").email("Invalid email format").max(254, "Email too long").refine(
28
- (email) => {
29
- if (!email || typeof email !== "string") return false;
30
- const domain = email.split("@")[1];
31
- return domain && domain.includes(".") && domain.length > 3;
32
- },
33
- "Invalid email domain"
34
- ).transform((email) => sanitizeEmail(email));
35
- var emailSchema2 = z.string().min(1, "Email is required").email("Invalid email format");
36
- var nameSchema2 = z.string().min(1, "Name is required").max(100, "Name too long").regex(/^[a-zA-Z\s'-]+$/, "Name contains invalid characters");
37
- var phoneSchema2 = z.string().regex(/^[\+]?[1-9][\d]{0,15}$/, "Invalid phone number format");
38
- var urlSchema2 = z.string().url("Invalid URL format");
39
- var dateSchema2 = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Invalid date format (YYYY-MM-DD)");
40
- var secureLoginSchema2 = z.object({
41
- email: secureEmailSchema,
42
- password: z.string().min(1, "Password is required")
43
- });
44
- function sanitizeEmail(email) {
45
- if (!email || typeof email !== "string") {
46
- return "";
47
- }
48
- return email.toLowerCase().trim();
49
- }
50
- function sanitizeString(input) {
51
- if (!input || typeof input !== "string") {
52
- return "";
53
- }
54
- return input.replace(/[<>]/g, "").replace(/javascript:/gi, "").replace(/on\w+=/gi, "").trim();
55
- }
56
-
57
- // src/validation/csrf.ts
58
- init_secureStorage();
59
- var CSRFManager = class {
60
- constructor() {
61
- this.tokenCache = /* @__PURE__ */ new Map();
62
- this.TOKEN_EXPIRY = 30 * 60 * 1e3;
63
- // 30 minutes
64
- this.MAX_TOKENS_PER_SESSION = 10;
65
- }
66
- /**
67
- * Generate a new CSRF token for the current session
68
- */
69
- async generateToken(sessionId) {
70
- try {
71
- await this.cleanupExpiredTokens();
72
- const sessionTokens = Array.from(this.tokenCache.values()).filter((data) => data.sessionId === sessionId && !data.used);
73
- if (sessionTokens.length >= this.MAX_TOKENS_PER_SESSION) {
74
- const oldest = sessionTokens.sort((a, b) => a.timestamp - b.timestamp)[0];
75
- this.tokenCache.delete(oldest.token);
76
- }
77
- const tokenBytes = new Uint8Array(32);
78
- crypto.getRandomValues(tokenBytes);
79
- const token = Array.from(
80
- tokenBytes,
81
- (byte) => byte.toString(16).padStart(2, "0")
82
- ).join("");
83
- const tokenData = {
84
- token,
85
- sessionId,
86
- timestamp: Date.now(),
87
- used: false
88
- };
89
- this.tokenCache.set(token, tokenData);
90
- await this.persistTokens();
91
- return token;
92
- } catch (error) {
93
- throw new Error("CSRF token generation failed");
94
- }
95
- }
96
- /**
97
- * Validate and consume a CSRF token
98
- */
99
- async validateToken(token, sessionId) {
100
- try {
101
- if (this.tokenCache.size === 0) {
102
- await this.loadTokens();
103
- }
104
- const tokenData = this.tokenCache.get(token);
105
- if (!tokenData) {
106
- return false;
107
- }
108
- if (tokenData.sessionId !== sessionId) {
109
- return false;
110
- }
111
- if (tokenData.used) {
112
- return false;
113
- }
114
- if (Date.now() - tokenData.timestamp > this.TOKEN_EXPIRY) {
115
- this.tokenCache.delete(token);
116
- await this.persistTokens();
117
- return false;
118
- }
119
- tokenData.used = true;
120
- this.tokenCache.set(token, tokenData);
121
- await this.persistTokens();
122
- return true;
123
- } catch (error) {
124
- return false;
125
- }
126
- }
127
- /**
128
- * Get current valid token for session
129
- */
130
- async getCurrentToken(sessionId) {
131
- if (this.tokenCache.size === 0) {
132
- await this.loadTokens();
133
- }
134
- for (const [token, data] of this.tokenCache.entries()) {
135
- if (data.sessionId === sessionId && !data.used && Date.now() - data.timestamp < this.TOKEN_EXPIRY) {
136
- return token;
137
- }
138
- }
139
- return await this.generateToken(sessionId);
140
- }
141
- /**
142
- * Clean up expired and used tokens
143
- */
144
- async cleanupExpiredTokens() {
145
- const now = Date.now();
146
- const expiredTokens = [];
147
- for (const [token, data] of this.tokenCache.entries()) {
148
- if (data.used || now - data.timestamp > this.TOKEN_EXPIRY) {
149
- expiredTokens.push(token);
150
- }
151
- }
152
- expiredTokens.forEach((token) => this.tokenCache.delete(token));
153
- if (expiredTokens.length > 0) {
154
- await this.persistTokens();
155
- }
156
- }
157
- /**
158
- * Persist tokens to secure storage
159
- */
160
- async persistTokens() {
161
- try {
162
- const tokensArray = Array.from(this.tokenCache.entries());
163
- await secureStorage.setItem(
164
- "csrf_tokens",
165
- JSON.stringify(tokensArray),
166
- { encrypt: true, expiry: this.TOKEN_EXPIRY }
167
- );
168
- } catch (error) {
169
- }
170
- }
171
- /**
172
- * Load tokens from secure storage
173
- */
174
- async loadTokens() {
175
- try {
176
- const tokensData = await secureStorage.getItem("csrf_tokens");
177
- if (tokensData) {
178
- const tokensArray = JSON.parse(tokensData);
179
- this.tokenCache = new Map(tokensArray);
180
- await this.cleanupExpiredTokens();
181
- }
182
- } catch (error) {
183
- this.tokenCache.clear();
184
- }
185
- }
186
- /**
187
- * Clear all tokens for session
188
- */
189
- async clearSession(sessionId) {
190
- const tokensToRemove = [];
191
- for (const [token, data] of this.tokenCache.entries()) {
192
- if (data.sessionId === sessionId) {
193
- tokensToRemove.push(token);
194
- }
195
- }
196
- tokensToRemove.forEach((token) => this.tokenCache.delete(token));
197
- await this.persistTokens();
198
- }
199
- };
200
- var csrfManager = new CSRFManager();
201
- async function generateCSRFToken(sessionId) {
202
- return csrfManager.generateToken(sessionId);
203
- }
204
- async function validateCSRFToken(token, sessionId) {
205
- return csrfManager.validateToken(token, sessionId);
206
- }
207
- async function getCSRFToken(sessionId) {
208
- return csrfManager.getCurrentToken(sessionId);
209
- }
210
-
211
- // src/validation/sqlInjectionProtection.ts
212
- import { z as z2 } from "zod";
213
- var SQL_INJECTION_PATTERNS = [
214
- /(\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC|EXECUTE|UNION|SCRIPT|JAVASCRIPT)\b)/i,
215
- /(\'|(\\\')|(\'\')|(\"|(\\\")|(\\")))|(\\x)|(\\u)/i,
216
- /((%27)|(')|(%6F)|o|(%4F)|(%72)|r|(%52))/i,
217
- // '|%27|' OR
218
- /((%27)|(')|(%55)|u|(%55)|(%4E)|n|(%4E)|(%49)|i|(%49)|(%4F)|o|(%4F)|(%4E)|n|(%4E))/i,
219
- // '|%27|' UNION
220
- /((%3D)|(=))[^\n]*((%27)|(')|((\\x27))|((\\x2D))|((\\x23)))/i,
221
- /(w*((%27)|(')|(%6F)|o|(%4F)|(%72)|r|(%52)))/i,
222
- /((%27)|(')|(''))+union/i,
223
- /exec(\+|\s)+(s|x)p\w+/i,
224
- /\b(and|or)\b.+?(=|<|>|\bin\b|\blike\b)/i,
225
- /\bunion\b.+?\bselect\b/i,
226
- /\bdrop\b.+?\btable\b/i,
227
- /\binsert\b.+?\binto\b/i,
228
- /\bdelete\b.+?\bfrom\b/i,
229
- /\bupdate\b.+?\bset\b/i,
230
- /(;|(\\x3B)).+?(drop|create|alter|exec|execute|insert|update|delete)/i,
231
- /(%3B|;).+?(%44|%64|d)(%52|%72|r)(%4F|%6F|o)(%50|%70|p)/i
232
- ];
233
- var DANGEROUS_CHARS = /[';\"\\%]/g;
234
- var searchQuerySchema = z2.string().max(500, "Search query too long").refine(
235
- (query) => {
236
- return !SQL_INJECTION_PATTERNS.some((pattern) => pattern.test(query));
237
- },
238
- "Invalid characters detected in search query"
239
- ).transform((query) => sanitizeSearchQuery(query));
240
- var sqlIdentifierSchema = z2.string().min(1, "Identifier cannot be empty").max(63, "Identifier too long").regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/, "Invalid identifier format").refine(
241
- (identifier) => {
242
- const reservedWords = [
243
- "SELECT",
244
- "INSERT",
245
- "UPDATE",
246
- "DELETE",
247
- "DROP",
248
- "CREATE",
249
- "ALTER",
250
- "FROM",
251
- "WHERE",
252
- "JOIN",
253
- "UNION",
254
- "ORDER",
255
- "GROUP",
256
- "HAVING"
257
- ];
258
- return !reservedWords.includes(identifier.toUpperCase());
259
- },
260
- "Identifier cannot be a reserved SQL keyword"
261
- );
262
- var orderBySchema = z2.string().regex(/^[a-zA-Z_][a-zA-Z0-9_]*(\s+(ASC|DESC|asc|desc))?$/, "Invalid order by format");
263
- var limitOffsetSchema = z2.number().int("Must be an integer").min(0, "Must be non-negative").max(1e3, "Limit too large");
264
- function sanitizeSearchQuery(query) {
265
- return query.replace(DANGEROUS_CHARS, "").replace(/\s+/g, " ").trim().slice(0, 500);
266
- }
267
- function escapeLikeQuery(query) {
268
- return query.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
269
- }
270
- function sanitizeFilters(filters) {
271
- const sanitized = {};
272
- for (const [key, value] of Object.entries(filters)) {
273
- const keyValidation = sqlIdentifierSchema.safeParse(key);
274
- if (!keyValidation.success) {
275
- console.warn(`[SECURITY] Invalid filter key detected and removed: ${key}`);
276
- continue;
277
- }
278
- if (typeof value === "string") {
279
- const valueValidation = searchQuerySchema.safeParse(value);
280
- if (valueValidation.success) {
281
- sanitized[key] = valueValidation.data;
282
- }
283
- } else if (typeof value === "number") {
284
- if (Number.isFinite(value)) {
285
- sanitized[key] = value;
286
- }
287
- } else if (typeof value === "boolean") {
288
- sanitized[key] = value;
289
- } else if (Array.isArray(value)) {
290
- const sanitizedArray = value.filter((item) => typeof item === "string" || typeof item === "number").map((item) => typeof item === "string" ? sanitizeSearchQuery(item) : item).slice(0, 100);
291
- if (sanitizedArray.length > 0) {
292
- sanitized[key] = sanitizedArray;
293
- }
294
- }
295
- }
296
- return sanitized;
297
- }
298
- function buildSafeQueryParams(params) {
299
- const safe = {};
300
- if (params.select) {
301
- const selectFields = params.select.split(",").map((field) => field.trim());
302
- const validFields = selectFields.filter((field) => {
303
- return sqlIdentifierSchema.safeParse(field).success;
304
- });
305
- if (validFields.length > 0) {
306
- safe.select = validFields.join(", ");
307
- }
308
- }
309
- if (params.filters) {
310
- safe.filters = sanitizeFilters(params.filters);
311
- }
312
- if (params.orderBy) {
313
- const orderByValidation = orderBySchema.safeParse(params.orderBy);
314
- if (orderByValidation.success) {
315
- safe.orderBy = orderByValidation.data;
316
- }
317
- }
318
- if (params.limit !== void 0) {
319
- const limitValidation = limitOffsetSchema.safeParse(params.limit);
320
- if (limitValidation.success) {
321
- safe.limit = limitValidation.data;
322
- }
323
- }
324
- if (params.offset !== void 0) {
325
- const offsetValidation = limitOffsetSchema.safeParse(params.offset);
326
- if (offsetValidation.success) {
327
- safe.offset = offsetValidation.data;
328
- }
329
- }
330
- if (params.search) {
331
- const searchValidation = searchQuerySchema.safeParse(params.search);
332
- if (searchValidation.success) {
333
- safe.search = searchValidation.data;
334
- }
335
- }
336
- return safe;
337
- }
338
- function detectSQLInjection(input) {
339
- const detectedPatterns = [];
340
- let maxRisk = "low";
341
- SQL_INJECTION_PATTERNS.forEach((pattern, index) => {
342
- if (pattern.test(input)) {
343
- detectedPatterns.push(`Pattern ${index + 1}`);
344
- if (index < 3) {
345
- maxRisk = "critical";
346
- } else if (index < 7 && maxRisk !== "critical") {
347
- maxRisk = "high";
348
- } else if (index < 12 && !["critical", "high"].includes(maxRisk)) {
349
- maxRisk = "medium";
350
- }
351
- }
352
- });
353
- return {
354
- isSuspicious: detectedPatterns.length > 0,
355
- patterns: detectedPatterns,
356
- riskLevel: maxRisk
357
- };
358
- }
359
-
360
- // src/validation/passwordSchema.ts
361
- import { z as z3 } from "zod";
362
- var COMMON_PASSWORDS = /* @__PURE__ */ new Set([
363
- "password",
364
- "123456",
365
- "123456789",
366
- "qwerty",
367
- "abc123",
368
- "password123",
369
- "admin",
370
- "letmein",
371
- "welcome",
372
- "monkey",
373
- "1234567890",
374
- "password1"
375
- ]);
376
- var WEAK_PATTERNS = [
377
- /^(.)\1+$/,
378
- // All same character
379
- /^(012|123|234|345|456|567|678|789|890|987|876|765|654|543|432|321|210)+/,
380
- // Sequential numbers
381
- /^(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
382
- // Sequential letters
383
- ];
384
- var securePasswordSchema2 = z3.string().min(8, "Password must be at least 8 characters long").max(128, "Password must not exceed 128 characters").refine(
385
- (password) => /[a-z]/.test(password),
386
- "Password must contain at least one lowercase letter"
387
- ).refine(
388
- (password) => /[A-Z]/.test(password),
389
- "Password must contain at least one uppercase letter"
390
- ).refine(
391
- (password) => /\d/.test(password),
392
- "Password must contain at least one number"
393
- ).refine(
394
- (password) => /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password),
395
- "Password must contain at least one special character"
396
- ).refine(
397
- (password) => !COMMON_PASSWORDS.has(password.toLowerCase()),
398
- "Password is too common. Please choose a stronger password"
399
- ).refine(
400
- (password) => !WEAK_PATTERNS.some((pattern) => pattern.test(password)),
401
- "Password contains weak patterns. Please choose a more complex password"
402
- ).refine(
403
- (password) => {
404
- const keyboardPatterns = ["qwerty", "asdfgh", "zxcvbn", "1234567890"];
405
- return !keyboardPatterns.some(
406
- (pattern) => password.toLowerCase().includes(pattern)
407
- );
408
- },
409
- "Password contains keyboard patterns. Please choose a more secure password"
410
- );
411
- var passwordSchema2 = z3.string().min(6, "Password must be at least 6 characters long").max(128, "Password must not exceed 128 characters");
412
- function calculatePasswordStrength(password) {
413
- let score = 0;
414
- const feedback = [];
415
- if (password.length >= 8) score += 20;
416
- else if (password.length >= 6) score += 10;
417
- else feedback.push("Use at least 8 characters");
418
- if (/[a-z]/.test(password)) score += 15;
419
- else feedback.push("Add lowercase letters");
420
- if (/[A-Z]/.test(password)) score += 15;
421
- else feedback.push("Add uppercase letters");
422
- if (/\d/.test(password)) score += 15;
423
- else feedback.push("Add numbers");
424
- if (/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password)) score += 15;
425
- else feedback.push("Add special characters");
426
- if (password.length >= 12) score += 10;
427
- if (/[^a-zA-Z0-9]/.test(password)) score += 10;
428
- if (COMMON_PASSWORDS.has(password.toLowerCase())) {
429
- score -= 30;
430
- feedback.push("Avoid common passwords");
431
- }
432
- if (WEAK_PATTERNS.some((pattern) => pattern.test(password))) {
433
- score -= 20;
434
- feedback.push("Avoid predictable patterns");
435
- }
436
- let level;
437
- if (score < 30) level = "very-weak";
438
- else if (score < 50) level = "weak";
439
- else if (score < 70) level = "fair";
440
- else if (score < 90) level = "good";
441
- else level = "strong";
442
- return { score: Math.max(0, Math.min(100, score)), feedback, level };
443
- }
444
- export {
445
- buildSafeQueryParams,
446
- calculatePasswordStrength,
447
- changePasswordSchema,
448
- combineSchemas,
449
- contactFormSchema,
450
- csrfManager,
451
- dateSchema,
452
- detectSQLInjection,
453
- emailSchema,
454
- escapeLikeQuery,
455
- generateCSRFToken,
456
- getCSRFToken,
457
- limitOffsetSchema,
458
- loginSchema,
459
- nameSchema,
460
- orderBySchema,
461
- passwordResetSchema,
462
- passwordSchema,
463
- phoneSchema,
464
- pickSchema,
465
- registrationSchema,
466
- sanitizeEmail,
467
- sanitizeFilters,
468
- sanitizeSearchQuery,
469
- sanitizeString,
470
- searchQuerySchema,
471
- secureEmailSchema,
472
- secureLoginSchema,
473
- securePasswordSchema,
474
- sqlIdentifierSchema,
475
- urlSchema,
476
- userProfileSchema,
477
- validateCSRFToken
478
- };
479
- //# sourceMappingURL=validation.js.map
@@ -1,24 +0,0 @@
1
- @import "tailwindcss";
2
-
3
- @theme inline {
4
- /* Semantic token mapping */
5
- --color-border: var(--color-app-main-500);
6
- --color-input: var(--color-app-sec-200);
7
- --color-ring: var(--color-app-main-950);
8
- --color-background: var(--color-app-main-50);
9
- --color-foreground: var(--color-app-main-950);
10
- --color-primary: var(--color-app-main-600);
11
- --color-primary-foreground: var(--color-app-main-50);
12
- --color-secondary: var(--color-app-sec-400);
13
- --color-secondary-foreground: var(--color-app-main-950);
14
- --color-destructive: var(--color-app-acc-700);
15
- --color-destructive-foreground: var(--color-app-main-50);
16
- --color-muted: var(--color-app-sec-100);
17
- --color-muted-foreground: var(--color-app-main-700);
18
- --color-accent: var(--color-app-acc-400);
19
- --color-accent-foreground: var(--color-app-main-950);
20
- --color-popover: var(--color-app-main-50);
21
- --color-popover-foreground: var(--color-app-main-950);
22
- --color-card: var(--color-app-main-50);
23
- --color-card-foreground: var(--color-app-main-950);
24
- }