@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.
- package/dist/{AuthService-D4646R4b.d.ts → AuthService-DYuQPJj6.d.ts} +0 -9
- package/dist/{DataTable-DGZDJUYM.js → DataTable-WTS4IRF2.js} +7 -8
- package/dist/{PublicLoadingSpinner-DgDWTFqn.d.ts → PublicLoadingSpinner-CaoRbHvJ.d.ts} +30 -4
- package/dist/{UnifiedAuthProvider-UACKFATV.js → UnifiedAuthProvider-6C47WIML.js} +3 -4
- package/dist/{chunk-D6BOFXYR.js → chunk-35ZDPMBM.js} +3 -3
- package/dist/{chunk-CGURJ27Z.js → chunk-4MXVZVNS.js} +2 -2
- package/dist/{chunk-ZYJ6O5CA.js → chunk-C43QIDN3.js} +2 -2
- package/dist/{chunk-VKOCWWVY.js → chunk-CX5M4ZAG.js} +1 -6
- package/dist/{chunk-VKOCWWVY.js 3.map → chunk-CX5M4ZAG.js.map} +1 -1
- package/dist/{chunk-HFBOFZ3Z.js → chunk-DHMFMXFV.js} +258 -243
- package/dist/chunk-DHMFMXFV.js.map +1 -0
- package/dist/{chunk-RIEJGKD3.js → chunk-ESJTIADP.js} +15 -6
- package/dist/{chunk-RIEJGKD3.js.map → chunk-ESJTIADP.js.map} +1 -1
- package/dist/{chunk-SMJZMKYN.js → chunk-GEVIB2UB.js} +43 -10
- package/dist/chunk-GEVIB2UB.js.map +1 -0
- package/dist/{chunk-TDNI6ZWL.js → chunk-IJOZZOGT.js} +7 -7
- package/dist/chunk-IJOZZOGT.js.map +1 -0
- package/dist/{chunk-GZRXOUBE.js → chunk-M6DDYFUD.js} +2 -2
- package/dist/chunk-M6DDYFUD.js.map +1 -0
- package/dist/{chunk-B4GZ2BXO.js → chunk-NZGLXZGP.js} +3 -3
- package/dist/{chunk-NZ32EONV.js → chunk-QWNJCQXZ.js} +2 -2
- package/dist/{chunk-FKFHZUGF.js → chunk-XN6GWKMV.js} +43 -56
- package/dist/chunk-XN6GWKMV.js.map +1 -0
- package/dist/{chunk-BHWIUEYH.js → chunk-ZBLK676C.js} +1 -61
- package/dist/chunk-ZBLK676C.js.map +1 -0
- package/dist/{chunk-QPI2CCBA.js → chunk-ZPJMYGEP.js} +149 -96
- package/dist/chunk-ZPJMYGEP.js.map +1 -0
- package/dist/components.d.ts +1 -1
- package/dist/components.js +11 -11
- package/dist/{formatting-B1jSqgl-.d.ts → formatting-DFcCxUEk.d.ts} +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +9 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +19 -17
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +2 -3
- package/dist/rbac/index.js +7 -8
- package/dist/styles/index.d.ts +1 -1
- package/dist/styles/index.js +5 -3
- package/dist/theming/runtime.d.ts +73 -1
- package/dist/theming/runtime.js +5 -5
- package/dist/{usePublicRouteParams-BdF8bZgs.d.ts → usePublicRouteParams-Dyt1tzI9.d.ts} +60 -8
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +5 -5
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- 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 +6 -6
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +6 -6
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- 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 +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- 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 +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- 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 +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +7 -7
- package/docs/api/interfaces/PublicErrorBoundaryState.md +5 -5
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +7 -7
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +51 -12
- package/docs/api/interfaces/PublicPageLayoutProps.md +72 -12
- 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 +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- 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 +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +140 -30
- package/docs/best-practices/README.md +1 -1
- package/docs/implementation-guides/datatable-filtering.md +313 -0
- package/docs/implementation-guides/datatable-rbac-usage.md +317 -0
- package/docs/implementation-guides/hierarchical-datatable.md +850 -0
- package/docs/implementation-guides/large-datasets.md +281 -0
- package/docs/implementation-guides/performance.md +403 -0
- package/docs/implementation-guides/public-pages.md +4 -4
- package/docs/migration/quick-migration-guide.md +320 -0
- package/docs/rbac/quick-start.md +16 -16
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +1 -1
- package/docs/troubleshooting/debugging.md +1117 -0
- package/docs/troubleshooting/migration.md +918 -0
- package/examples/public-pages/CorrectPublicPageImplementation.tsx +30 -30
- package/examples/public-pages/PublicEventPage.tsx +41 -41
- package/examples/public-pages/PublicPageApp.tsx +33 -33
- package/examples/public-pages/PublicPageUsageExample.tsx +30 -30
- package/package.json +4 -4
- package/src/__tests__/hooks/usePermissions.test.ts +265 -0
- package/src/components/DataTable/DataTable.test.tsx +9 -38
- package/src/components/DataTable/DataTable.tsx +0 -7
- package/src/components/DataTable/components/DataTableCore.tsx +66 -136
- package/src/components/DataTable/components/DataTableModals.tsx +25 -22
- package/src/components/DataTable/components/EditableRow.tsx +118 -42
- package/src/components/DataTable/components/UnifiedTableBody.tsx +129 -76
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +33 -14
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +17 -5
- package/src/components/DataTable/utils/exportUtils.ts +3 -2
- package/src/components/Dialog/Dialog.tsx +1 -1
- package/src/components/Dialog/README.md +24 -24
- package/src/components/Dialog/examples/BasicHtmlTest.tsx +2 -2
- package/src/components/Dialog/examples/DebugHtmlExample.tsx +6 -6
- package/src/components/Dialog/examples/HtmlDialogExample.tsx +2 -2
- package/src/components/Dialog/examples/SimpleHtmlTest.tsx +3 -3
- package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +4 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -1
- package/src/components/PublicLayout/EventLogo.tsx +175 -0
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +22 -18
- package/src/components/PublicLayout/PublicLoadingSpinner.tsx +22 -14
- package/src/components/PublicLayout/PublicPageHeader.tsx +133 -40
- package/src/components/PublicLayout/PublicPageLayout.tsx +75 -72
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +1 -1
- package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +8 -8
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +23 -16
- package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +86 -14
- package/src/examples/CorrectPublicPageImplementation.tsx +30 -30
- package/src/examples/PublicEventPage.tsx +41 -41
- package/src/examples/PublicPageApp.tsx +33 -33
- package/src/examples/PublicPageUsageExample.tsx +30 -30
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
- package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +10 -3
- package/src/hooks/index.ts +1 -1
- package/src/hooks/public/usePublicEventLogo.ts +285 -0
- package/src/hooks/public/usePublicRouteParams.ts +21 -4
- package/src/hooks/useEventTheme.test.ts +119 -43
- package/src/hooks/useEventTheme.ts +84 -55
- package/src/index.ts +3 -1
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +630 -0
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +496 -0
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
- package/src/rbac/secureClient.ts +4 -2
- package/src/services/EventService.ts +0 -66
- package/src/services/__tests__/EventService.eventColours.test.ts +44 -40
- package/src/styles/index.ts +1 -1
- package/src/theming/__tests__/parseEventColours.test.ts +209 -0
- package/src/theming/parseEventColours.ts +123 -0
- package/src/theming/runtime.ts +3 -0
- package/src/types/__tests__/file-reference.test.ts +447 -0
- package/src/utils/formatDate.test.ts +11 -11
- package/src/utils/formatting.ts +3 -2
- package/dist/chunk-BDZUMRBD.js 3.map +0 -1
- package/dist/chunk-BHWIUEYH.js.map +0 -1
- package/dist/chunk-CGURJ27Z.js.map +0 -1
- package/dist/chunk-FKFHZUGF.js.map +0 -1
- package/dist/chunk-GKHF54DI 2.js +0 -619
- package/dist/chunk-GKHF54DI.js 2.map +0 -1
- package/dist/chunk-GZRXOUBE.js.map +0 -1
- package/dist/chunk-HFBOFZ3Z.js.map +0 -1
- package/dist/chunk-NZ32EONV.js.map +0 -1
- package/dist/chunk-O3NWNXDY 2.js +0 -76
- package/dist/chunk-QPI2CCBA.js.map +0 -1
- package/dist/chunk-SMJZMKYN.js.map +0 -1
- package/dist/chunk-TDNI6ZWL.js 2.map +0 -1
- package/dist/chunk-TDNI6ZWL.js.map +0 -1
- package/dist/chunk-VKOCWWVY.js.map +0 -1
- package/dist/chunk-WP5I5GLN 2.js +0 -1564
- package/dist/index 3.js +0 -856
- package/dist/providers 3.js +0 -38
- package/dist/providers.js 3.map +0 -1
- package/dist/types 3.js +0 -128
- package/dist/types.js 3.map +0 -1
- package/dist/useInactivityTracker-MRUU55XI.js 3.map +0 -1
- package/dist/utils.js 3.map +0 -1
- package/dist/validation 3.js +0 -479
- package/src/styles/semantic.css +0 -24
- /package/dist/{DataTable-DGZDJUYM.js.map → DataTable-WTS4IRF2.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-UACKFATV.js.map → UnifiedAuthProvider-6C47WIML.js.map} +0 -0
- /package/dist/{chunk-D6BOFXYR.js.map → chunk-35ZDPMBM.js.map} +0 -0
- /package/dist/{chunk-CGURJ27Z.js 2.map → chunk-4MXVZVNS.js.map} +0 -0
- /package/dist/{chunk-ZYJ6O5CA.js.map → chunk-C43QIDN3.js.map} +0 -0
- /package/dist/{chunk-B4GZ2BXO.js.map → chunk-NZGLXZGP.js.map} +0 -0
- /package/dist/{chunk-NZ32EONV.js 2.map → chunk-QWNJCQXZ.js.map} +0 -0
package/dist/validation 3.js
DELETED
|
@@ -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
|
package/src/styles/semantic.css
DELETED
|
@@ -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
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|