UNPKG

fortifyjs-react

Version:

React integration for Nehonix FortifyJS - Secure state management with enhanced object operations

1,254 lines (1,235 loc) 44.1 kB
'use strict'; var React = require('react'); var fortify2Js = require('fortify2-js'); /** * Nehonix FortifyJS React Security Context * Modular security context for React applications */ /** * Default security configuration */ const DEFAULT_SECURITY_CONFIG = { encryptionLevel: "enhanced", defaultSensitiveKeys: [ "password", "secret", "token", "key", "auth", "credential", "private", "confidential", "ssn", "credit", "card", "cvv", "pin", ], enableMonitoring: true, performance: { enableCaching: true, cacheSize: 100, enableLazyLoading: true, }, memory: { autoCleanup: true, cleanupInterval: 30000, // 30 seconds maxMemoryUsage: 50 * 1024 * 1024, // 50MB }, development: { enableDebugMode: process.env.NODE_ENV === "development", logLevel: process.env.NODE_ENV === "development" ? "debug" : "error", enablePerformanceMetrics: true, }, }; /** * Security context for managing global security settings */ const SecurityContext = React.createContext(null); /** * Hook to access security context * @returns Security context value * @throws Error if used outside SecurityProvider */ function useSecurityContext() { const context = React.useContext(SecurityContext); if (!context) { throw new Error("useSecurityContext must be used within a SecurityProvider. " + "Make sure to wrap your component tree with <SecureProvider>."); } return context; } /** * Hook to access security configuration * @returns Current security configuration */ function useSecurityConfig() { const { config } = useSecurityContext(); return config; } /** * Hook to check if a key should be treated as sensitive * @param key - The key to check * @returns Whether the key is sensitive */ function useIsSensitiveKey(key) { const { config } = useSecurityContext(); const sensitiveKeys = config.defaultSensitiveKeys || []; // Check exact match if (sensitiveKeys.includes(key.toLowerCase())) { return true; } // Check if key contains sensitive patterns return sensitiveKeys.some((pattern) => key.toLowerCase().includes(pattern.toLowerCase())); } /** * Hook to access security metrics * @returns Current security metrics */ function useSecurityMetrics() { const { getMetrics } = useSecurityContext(); return getMetrics(); } /** * Hook to control debug mode * @returns Debug mode controls */ function useDebugMode() { const { debugMode, setDebugMode } = useSecurityContext(); return { enabled: debugMode, enable: () => setDebugMode(true), disable: () => setDebugMode(false), toggle: () => setDebugMode(!debugMode), }; } /** * Hook to register/unregister components for monitoring * @param componentId - Unique component identifier * @param metadata - Component metadata */ function useComponentRegistration(componentId, metadata = {}) { const { registerComponent, unregisterComponent } = useSecurityContext(); // Register component on mount React.useEffect(() => { registerComponent(componentId, { ...metadata, registeredAt: new Date(), componentType: "react-component", }); // Unregister on unmount return () => { unregisterComponent(componentId); }; }, [componentId, registerComponent, unregisterComponent]); } /** * Hook to get performance metrics for the current component * @param componentId - Component identifier * @returns Performance metrics */ function useComponentMetrics(componentId) { useSecurityContext(); const [metrics, setMetrics] = React.useState({ renderCount: 0, averageRenderTime: 0, lastRenderTime: 0, }); // Track render performance React.useEffect(() => { const startTime = performance.now(); return () => { const endTime = performance.now(); const renderTime = endTime - startTime; setMetrics((prev) => ({ renderCount: prev.renderCount + 1, averageRenderTime: (prev.averageRenderTime * prev.renderCount + renderTime) / (prev.renderCount + 1), lastRenderTime: renderTime, })); }; }); return metrics; } /** * Utility function to merge security configurations * @param base - Base configuration * @param override - Override configuration * @returns Merged configuration */ function mergeSecurityConfig(base, override) { return { ...base, ...override, defaultSensitiveKeys: [ ...(base.defaultSensitiveKeys || []), ...(override.defaultSensitiveKeys || []), ], performance: { ...base.performance, ...override.performance, }, memory: { ...base.memory, ...override.memory, }, development: { ...base.development, ...override.development, }, }; } /** * Utility function to validate security configuration * @param config - Configuration to validate * @throws Error if configuration is invalid */ function validateSecurityConfig(config) { if (config.memory?.maxMemoryUsage && config.memory.maxMemoryUsage < 0) { throw new Error("maxMemoryUsage must be a positive number"); } if (config.memory?.cleanupInterval && config.memory.cleanupInterval < 1000) { throw new Error("cleanupInterval must be at least 1000ms"); } if (config.performance?.cacheSize && config.performance.cacheSize < 1) { throw new Error("cacheSize must be at least 1"); } const validEncryptionLevels = ["basic", "enhanced", "military"]; if (config.encryptionLevel && !validEncryptionLevels.includes(config.encryptionLevel)) { throw new Error(`encryptionLevel must be one of: ${validEncryptionLevels.join(", ")}`); } const validLogLevels = ["none", "error", "warn", "info", "debug"]; if (config.development?.logLevel && !validLogLevels.includes(config.development.logLevel)) { throw new Error(`logLevel must be one of: ${validLogLevels.join(", ")}`); } } /** * FortifyJS React useSecureState Hook * Secure state management with automatic encryption and enhanced operations */ /** * Hook for secure state management with enhanced object operations * * @param initialValue - Initial state value * @param options - Configuration options * @returns Secure state management object * * @example * ```tsx * function UserProfile() { * const [user, setUser] = useSecureState({ * name: "John", * email: "john@example.com", * password: "secret123" * }, { * sensitiveKeys: ["password"], * autoEncrypt: true * }); * * return ( * <div> * <p>Name: {user.get("name")}</p> * <p>Email: {user.get("email")}</p> * // Password is automatically encrypted * </div> * ); * } * ``` */ function useSecureState(initialValue, options = {}) { const securityContext = useSecurityContext(); const isSensitiveKey = useIsSensitiveKey; // Configuration with defaults const config = { sensitiveKeys: options.sensitiveKeys || [], autoEncrypt: options.autoEncrypt ?? true, encryptionAlgorithm: options.encryptionAlgorithm || "AES-256-GCM", enableMonitoring: options.enableMonitoring ?? securityContext.config.enableMonitoring, debounceMs: options.debounceMs || 0, ...options, }; // Create secure object with initial value const [secureObject] = React.useState(() => { const obj = fortify2Js.createSecureObject(initialValue); // Set sensitive keys const allSensitiveKeys = [ ...config.sensitiveKeys, ...Object.keys(initialValue).filter((key) => isSensitiveKey(key)), ]; if (allSensitiveKeys.length > 0) { obj.setSensitiveKeys(allSensitiveKeys); } return obj; }); // Performance metrics const metricsRef = React.useRef({ updateCount: 0, lastUpdateTime: 0, totalUpdateTime: 0, }); // Force re-render when secure object changes const [, forceUpdate] = React.useState({}); const triggerUpdate = React.useCallback(() => { forceUpdate({}); }, []); // Debounced update function const debounceRef = React.useRef(null); const debouncedUpdate = React.useCallback(() => { if (config.debounceMs > 0) { if (debounceRef.current) { clearTimeout(debounceRef.current); } debounceRef.current = setTimeout(triggerUpdate, config.debounceMs); } else { triggerUpdate(); } }, [config.debounceMs, triggerUpdate]); // Set up event listeners for secure object changes React.useEffect(() => { const handleChange = () => { const startTime = performance.now(); // Update metrics metricsRef.current.updateCount++; metricsRef.current.lastUpdateTime = startTime; // Trigger re-render debouncedUpdate(); // Complete metrics const endTime = performance.now(); const duration = endTime - startTime; metricsRef.current.totalUpdateTime += duration; // Call user event handler if (config.validator) { const currentValue = secureObject.toObject(); if (!config.validator(currentValue)) { console.warn("useSecureState: Validation failed for current state"); } } }; // Listen to secure object events secureObject.addEventListener("set", handleChange); secureObject.addEventListener("delete", handleChange); secureObject.addEventListener("clear", handleChange); return () => { secureObject.removeEventListener("set", handleChange); secureObject.removeEventListener("delete", handleChange); secureObject.removeEventListener("clear", handleChange); if (debounceRef.current) { clearTimeout(debounceRef.current); } }; }, [secureObject, debouncedUpdate, config.validator]); // Cleanup on unmount React.useEffect(() => { return () => { secureObject.destroy(); }; }, [secureObject]); // setState function const setState = React.useCallback((value) => { performance.now(); try { if (typeof value === "function") { const currentValue = secureObject.toObject(); const newValue = value(currentValue); // Clear and set new values secureObject.clear(); Object.entries(newValue).forEach(([key, val]) => { secureObject.set(key, val); }); } else { // Clear and set new values secureObject.clear(); Object.entries(value).forEach(([key, val]) => { secureObject.set(key, val); }); } // Update sensitive keys if auto-detection is enabled if (config.autoEncrypt) { const newSensitiveKeys = Object.keys(secureObject.toObject()).filter((key) => isSensitiveKey(key)); if (newSensitiveKeys.length > 0) { const existingSensitive = secureObject.getSensitiveKeys(); const allSensitive = [ ...new Set([ ...existingSensitive, ...newSensitiveKeys, ]), ]; secureObject.setSensitiveKeys(allSensitive); } } } catch (error) { console.error("useSecureState: Error updating state:", error); throw error; } }, [secureObject, config.autoEncrypt, isSensitiveKey]); // getValue function const getValue = React.useCallback((key) => { return secureObject.get(key); }, [secureObject]); // setValue function const setValue = React.useCallback((key, value) => { secureObject.set(key, value); // Auto-detect sensitive keys if (config.autoEncrypt && isSensitiveKey(key)) { const existingSensitive = secureObject.getSensitiveKeys(); if (!existingSensitive.includes(key)) { secureObject.setSensitiveKeys([ ...existingSensitive, key, ]); } } }, [secureObject, config.autoEncrypt, isSensitiveKey]); // Calculate metrics const metrics = { updateCount: metricsRef.current.updateCount, lastUpdateTime: metricsRef.current.lastUpdateTime, averageUpdateTime: metricsRef.current.updateCount > 0 ? metricsRef.current.totalUpdateTime / metricsRef.current.updateCount : 0, }; return { state: secureObject, setState, getValue, setValue, isEncrypted: secureObject.getSensitiveKeys().length > 0, metrics, }; } /** * FortifyJS React useSecureObject Hook * Enhanced object operations with React integration */ /** * Hook for enhanced object operations with React integration * * @param initialData - Initial object data or data source * @param options - Configuration options * @returns Enhanced object management * * @example * ```tsx * function DataProcessor() { * const data = useSecureObject(rawData, { * autoCleanup: true, * enableEvents: true * }); * * const processedData = data.object * .filterNonSensitive() * .transform(value => value.toUpperCase()) * .compact(); * * return ( * <div> * <p>Processed {processedData.size} items</p> * <p>Ready: {data.isReady ? "Yes" : "No"}</p> * </div> * ); * } * ``` */ function useSecureObject(initialData, options = {}) { const securityContext = useSecurityContext(); // Configuration with defaults const config = { autoCleanup: options.autoCleanup ?? true, enableEvents: options.enableEvents ?? true, optimizationLevel: options.optimizationLevel || "balanced", memoryStrategy: options.memoryStrategy || "balanced", ...options, }; // State management const [secureObject, setSecureObject] = React.useState(null); const [isReady, setIsReady] = React.useState(false); const [isLoading, setIsLoading] = React.useState(true); const [error, setError] = React.useState(null); // Metadata tracking const metadataRef = React.useRef({ size: 0, sensitiveKeyCount: 0, lastModified: new Date(), }); // Memory management based on strategy const memoryConfig = { conservative: { maxSize: 1000, cleanupThreshold: 0.8 }, balanced: { maxSize: 5000, cleanupThreshold: 0.9 }, aggressive: { maxSize: 10000, cleanupThreshold: 0.95 }, }[config.memoryStrategy]; // Initialize secure object const initializeObject = React.useCallback(async () => { setIsLoading(true); setError(null); try { let data; if (typeof initialData === "function") { const result = initialData(); data = result instanceof Promise ? await result : result; } else { data = initialData; } const obj = fortify2Js.createSecureObject(data); // Set up event listeners if enabled if (config.enableEvents) { const updateMetadata = () => { metadataRef.current = { size: obj.size, sensitiveKeyCount: obj.getSensitiveKeys().length, lastModified: new Date(), }; }; obj.addEventListener("set", updateMetadata); obj.addEventListener("delete", updateMetadata); obj.addEventListener("clear", updateMetadata); obj.addEventListener("filtered", updateMetadata); } // Apply memory management if (obj.size > memoryConfig.maxSize) { console.warn(`useSecureObject: Object size (${obj.size}) exceeds recommended maximum (${memoryConfig.maxSize}). ` + "Consider using streaming operations for large datasets."); } setSecureObject(obj); setIsReady(true); // Initial metadata update metadataRef.current = { size: obj.size, sensitiveKeyCount: obj.getSensitiveKeys().length, lastModified: new Date(), }; } catch (err) { const error = err instanceof Error ? err : new Error(String(err)); setError(error); console.error("useSecureObject: Failed to initialize object:", error); } finally { setIsLoading(false); } }, [initialData, config.enableEvents, memoryConfig.maxSize]); // Initialize on mount React.useEffect(() => { initializeObject(); }, [initializeObject]); // Cleanup on unmount React.useEffect(() => { return () => { if (config.autoCleanup && secureObject) { secureObject.destroy(); } }; }, [config.autoCleanup, secureObject]); // Memory monitoring React.useEffect(() => { if (!secureObject || !config.enableEvents) return; const checkMemoryUsage = () => { const currentSize = secureObject.size; const threshold = memoryConfig.maxSize * memoryConfig.cleanupThreshold; if (currentSize > threshold) { console.warn(`useSecureObject: Memory usage approaching limit. ` + `Current: ${currentSize}, Threshold: ${threshold}`); // Trigger garbage collection hint if available if (typeof global !== "undefined" && global.gc) { global.gc(); } } }; const interval = setInterval(checkMemoryUsage, 10000); // Check every 10 seconds return () => clearInterval(interval); }, [secureObject, config.enableEvents, memoryConfig]); // Refresh function const refresh = React.useCallback(() => { initializeObject(); }, [initializeObject]); // Performance monitoring React.useEffect(() => { if (!securityContext.config.development?.enablePerformanceMetrics) return; const startTime = performance.now(); return () => { const endTime = performance.now(); const duration = endTime - startTime; if (duration > 100) { // Log slow operations console.debug(`useSecureObject: Component lifecycle took ${duration.toFixed(2)}ms`); } }; }, [securityContext.config.development?.enablePerformanceMetrics]); return { object: secureObject, refresh, isReady, isLoading, error, metadata: metadataRef.current, }; } /** * Hook for creating a secure object from static data * Simplified version of useSecureObject for static data * * @param data - Static object data * @param options - Configuration options * @returns Secure object */ function useStaticSecureObject(data, options = {}) { return useSecureObject(data, { ...options, autoCleanup: true }); } /** * Hook for creating a secure object from async data source * Specialized version for async data loading * * @param dataLoader - Async function that returns data * @param dependencies - Dependencies that trigger reload * @param options - Configuration options * @returns Secure object with loading states */ function useAsyncSecureObject(dataLoader, dependencies = [], options = {}) { const memoizedLoader = React.useCallback(dataLoader, dependencies); return useSecureObject(memoizedLoader, options); } var jsxRuntime = {exports: {}}; var reactJsxRuntime_production = {}; /** * @license React * react-jsx-runtime.production.js * * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var hasRequiredReactJsxRuntime_production; function requireReactJsxRuntime_production () { if (hasRequiredReactJsxRuntime_production) return reactJsxRuntime_production; hasRequiredReactJsxRuntime_production = 1; var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"); function jsxProd(type, config, maybeKey) { var key = null; void 0 !== maybeKey && (key = "" + maybeKey); void 0 !== config.key && (key = "" + config.key); if ("key" in config) { maybeKey = {}; for (var propName in config) "key" !== propName && (maybeKey[propName] = config[propName]); } else maybeKey = config; config = maybeKey.ref; return { $$typeof: REACT_ELEMENT_TYPE, type: type, key: key, ref: void 0 !== config ? config : null, props: maybeKey }; } reactJsxRuntime_production.Fragment = REACT_FRAGMENT_TYPE; reactJsxRuntime_production.jsx = jsxProd; reactJsxRuntime_production.jsxs = jsxProd; return reactJsxRuntime_production; } var reactJsxRuntime_development = {}; /** * @license React * react-jsx-runtime.development.js * * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var hasRequiredReactJsxRuntime_development; function requireReactJsxRuntime_development () { if (hasRequiredReactJsxRuntime_development) return reactJsxRuntime_development; hasRequiredReactJsxRuntime_development = 1; "production" !== process.env.NODE_ENV && (function () { function getComponentNameFromType(type) { if (null == type) return null; if ("function" === typeof type) return type.$$typeof === REACT_CLIENT_REFERENCE ? null : type.displayName || type.name || null; if ("string" === typeof type) return type; switch (type) { case REACT_FRAGMENT_TYPE: return "Fragment"; case REACT_PROFILER_TYPE: return "Profiler"; case REACT_STRICT_MODE_TYPE: return "StrictMode"; case REACT_SUSPENSE_TYPE: return "Suspense"; case REACT_SUSPENSE_LIST_TYPE: return "SuspenseList"; case REACT_ACTIVITY_TYPE: return "Activity"; } if ("object" === typeof type) switch ( ("number" === typeof type.tag && console.error( "Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue." ), type.$$typeof) ) { case REACT_PORTAL_TYPE: return "Portal"; case REACT_CONTEXT_TYPE: return (type.displayName || "Context") + ".Provider"; case REACT_CONSUMER_TYPE: return (type._context.displayName || "Context") + ".Consumer"; case REACT_FORWARD_REF_TYPE: var innerType = type.render; type = type.displayName; type || ((type = innerType.displayName || innerType.name || ""), (type = "" !== type ? "ForwardRef(" + type + ")" : "ForwardRef")); return type; case REACT_MEMO_TYPE: return ( (innerType = type.displayName || null), null !== innerType ? innerType : getComponentNameFromType(type.type) || "Memo" ); case REACT_LAZY_TYPE: innerType = type._payload; type = type._init; try { return getComponentNameFromType(type(innerType)); } catch (x) {} } return null; } function testStringCoercion(value) { return "" + value; } function checkKeyStringCoercion(value) { try { testStringCoercion(value); var JSCompiler_inline_result = !1; } catch (e) { JSCompiler_inline_result = !0; } if (JSCompiler_inline_result) { JSCompiler_inline_result = console; var JSCompiler_temp_const = JSCompiler_inline_result.error; var JSCompiler_inline_result$jscomp$0 = ("function" === typeof Symbol && Symbol.toStringTag && value[Symbol.toStringTag]) || value.constructor.name || "Object"; JSCompiler_temp_const.call( JSCompiler_inline_result, "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.", JSCompiler_inline_result$jscomp$0 ); return testStringCoercion(value); } } function getTaskName(type) { if (type === REACT_FRAGMENT_TYPE) return "<>"; if ( "object" === typeof type && null !== type && type.$$typeof === REACT_LAZY_TYPE ) return "<...>"; try { var name = getComponentNameFromType(type); return name ? "<" + name + ">" : "<...>"; } catch (x) { return "<...>"; } } function getOwner() { var dispatcher = ReactSharedInternals.A; return null === dispatcher ? null : dispatcher.getOwner(); } function UnknownOwner() { return Error("react-stack-top-frame"); } function hasValidKey(config) { if (hasOwnProperty.call(config, "key")) { var getter = Object.getOwnPropertyDescriptor(config, "key").get; if (getter && getter.isReactWarning) return !1; } return void 0 !== config.key; } function defineKeyPropWarningGetter(props, displayName) { function warnAboutAccessingKey() { specialPropKeyWarningShown || ((specialPropKeyWarningShown = !0), console.error( "%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)", displayName )); } warnAboutAccessingKey.isReactWarning = !0; Object.defineProperty(props, "key", { get: warnAboutAccessingKey, configurable: !0 }); } function elementRefGetterWithDeprecationWarning() { var componentName = getComponentNameFromType(this.type); didWarnAboutElementRef[componentName] || ((didWarnAboutElementRef[componentName] = !0), console.error( "Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release." )); componentName = this.props.ref; return void 0 !== componentName ? componentName : null; } function ReactElement( type, key, self, source, owner, props, debugStack, debugTask ) { self = props.ref; type = { $$typeof: REACT_ELEMENT_TYPE, type: type, key: key, props: props, _owner: owner }; null !== (void 0 !== self ? self : null) ? Object.defineProperty(type, "ref", { enumerable: !1, get: elementRefGetterWithDeprecationWarning }) : Object.defineProperty(type, "ref", { enumerable: !1, value: null }); type._store = {}; Object.defineProperty(type._store, "validated", { configurable: !1, enumerable: !1, writable: !0, value: 0 }); Object.defineProperty(type, "_debugInfo", { configurable: !1, enumerable: !1, writable: !0, value: null }); Object.defineProperty(type, "_debugStack", { configurable: !1, enumerable: !1, writable: !0, value: debugStack }); Object.defineProperty(type, "_debugTask", { configurable: !1, enumerable: !1, writable: !0, value: debugTask }); Object.freeze && (Object.freeze(type.props), Object.freeze(type)); return type; } function jsxDEVImpl( type, config, maybeKey, isStaticChildren, source, self, debugStack, debugTask ) { var children = config.children; if (void 0 !== children) if (isStaticChildren) if (isArrayImpl(children)) { for ( isStaticChildren = 0; isStaticChildren < children.length; isStaticChildren++ ) validateChildKeys(children[isStaticChildren]); Object.freeze && Object.freeze(children); } else console.error( "React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead." ); else validateChildKeys(children); if (hasOwnProperty.call(config, "key")) { children = getComponentNameFromType(type); var keys = Object.keys(config).filter(function (k) { return "key" !== k; }); isStaticChildren = 0 < keys.length ? "{key: someKey, " + keys.join(": ..., ") + ": ...}" : "{key: someKey}"; didWarnAboutKeySpread[children + isStaticChildren] || ((keys = 0 < keys.length ? "{" + keys.join(": ..., ") + ": ...}" : "{}"), console.error( 'A props object containing a "key" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />', isStaticChildren, children, keys, children ), (didWarnAboutKeySpread[children + isStaticChildren] = !0)); } children = null; void 0 !== maybeKey && (checkKeyStringCoercion(maybeKey), (children = "" + maybeKey)); hasValidKey(config) && (checkKeyStringCoercion(config.key), (children = "" + config.key)); if ("key" in config) { maybeKey = {}; for (var propName in config) "key" !== propName && (maybeKey[propName] = config[propName]); } else maybeKey = config; children && defineKeyPropWarningGetter( maybeKey, "function" === typeof type ? type.displayName || type.name || "Unknown" : type ); return ReactElement( type, children, self, source, getOwner(), maybeKey, debugStack, debugTask ); } function validateChildKeys(node) { "object" === typeof node && null !== node && node.$$typeof === REACT_ELEMENT_TYPE && node._store && (node._store.validated = 1); } var React$1 = React, REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"); var REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), ReactSharedInternals = React$1.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, hasOwnProperty = Object.prototype.hasOwnProperty, isArrayImpl = Array.isArray, createTask = console.createTask ? console.createTask : function () { return null; }; React$1 = { "react-stack-bottom-frame": function (callStackForError) { return callStackForError(); } }; var specialPropKeyWarningShown; var didWarnAboutElementRef = {}; var unknownOwnerDebugStack = React$1["react-stack-bottom-frame"].bind( React$1, UnknownOwner )(); var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner)); var didWarnAboutKeySpread = {}; reactJsxRuntime_development.Fragment = REACT_FRAGMENT_TYPE; reactJsxRuntime_development.jsx = function (type, config, maybeKey, source, self) { var trackActualOwner = 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++; return jsxDEVImpl( type, config, maybeKey, !1, source, self, trackActualOwner ? Error("react-stack-top-frame") : unknownOwnerDebugStack, trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask ); }; reactJsxRuntime_development.jsxs = function (type, config, maybeKey, source, self) { var trackActualOwner = 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++; return jsxDEVImpl( type, config, maybeKey, !0, source, self, trackActualOwner ? Error("react-stack-top-frame") : unknownOwnerDebugStack, trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask ); }; })(); return reactJsxRuntime_development; } if (process.env.NODE_ENV === 'production') { jsxRuntime.exports = requireReactJsxRuntime_production(); } else { jsxRuntime.exports = requireReactJsxRuntime_development(); } var jsxRuntimeExports = jsxRuntime.exports; /** * Global security provider component * Provides security context to all child components * * @example * ```tsx * function App() { * return ( * <SecureProvider * config={{ * encryptionLevel: "military", * enableMonitoring: true * }} * > * <UserProfile /> * <DataProcessor /> * </SecureProvider> * ); * } * ``` */ const SecureProvider = ({ config: userConfig, children, fallback = null, onError, }) => { // Merge user config with defaults const [config, setConfig] = React.useState(() => { try { const mergedConfig = mergeSecurityConfig(DEFAULT_SECURITY_CONFIG, userConfig); validateSecurityConfig(mergedConfig); return mergedConfig; } catch (error) { console.error("SecureProvider: Invalid configuration:", error); if (onError) { onError(error, { phase: "initialization" }); } return DEFAULT_SECURITY_CONFIG; } }); // Debug mode state const [debugMode, setDebugMode] = React.useState(config.development?.enableDebugMode ?? false); // Component registry for monitoring const registeredComponents = React.useRef({}); // Performance metrics const metricsRef = React.useRef({ componentRenders: 0, averageRenderTime: 0, memoryUsage: 0, operationCounts: {}, lastUpdate: new Date(), }); // Security metrics const securityMetricsRef = React.useRef({ totalOperations: 0, encryptedOperations: 0, totalOperationTime: 0, memoryUsage: 0, }); // Update configuration const updateConfig = React.useCallback((newConfig) => { try { const mergedConfig = mergeSecurityConfig(config, newConfig); validateSecurityConfig(mergedConfig); setConfig(mergedConfig); if (debugMode) { console.debug("SecureProvider: Configuration updated", mergedConfig); } } catch (error) { console.error("SecureProvider: Failed to update configuration:", error); if (onError) { onError(error, { phase: "configuration-update" }); } } }, [config, debugMode, onError]); // Get security metrics const getMetrics = React.useCallback(() => { const metrics = securityMetricsRef.current; return { totalOperations: metrics.totalOperations, encryptedOperations: metrics.encryptedOperations, averageOperationTime: metrics.totalOperations > 0 ? metrics.totalOperationTime / metrics.totalOperations : 0, memoryUsage: metrics.memoryUsage, }; }, []); // Register component const registerComponent = React.useCallback((componentId, metadata) => { registeredComponents.current[componentId] = { ...metadata, registeredAt: new Date(), }; if (debugMode) { console.debug(`SecureProvider: Registered component ${componentId}`, metadata); } }, [debugMode]); // Unregister component const unregisterComponent = React.useCallback((componentId) => { delete registeredComponents.current[componentId]; if (debugMode) { console.debug(`SecureProvider: Unregistered component ${componentId}`); } }, [debugMode]); // Get registered components const getRegisteredComponents = React.useCallback(() => { return { ...registeredComponents.current }; }, []); // Memory monitoring React.useEffect(() => { if (!config.memory?.autoCleanup) return; const interval = setInterval(() => { // Update memory usage metrics if (typeof performance !== "undefined" && performance.memory) { const memInfo = performance.memory; securityMetricsRef.current.memoryUsage = memInfo.usedJSHeapSize; // Check memory threshold const maxMemory = config.memory?.maxMemoryUsage || 50 * 1024 * 1024; if (memInfo.usedJSHeapSize > maxMemory * 0.9) { console.warn("SecureProvider: High memory usage detected. " + "Consider optimizing your secure objects."); } } // Clean up old component registrations const now = new Date(); const maxAge = 5 * 60 * 1000; // 5 minutes Object.entries(registeredComponents.current).forEach(([id, metadata]) => { if (now.getTime() - metadata.registeredAt.getTime() > maxAge) { delete registeredComponents.current[id]; } }); }, config.memory?.cleanupInterval || 30000); return () => clearInterval(interval); }, [config.memory]); // Performance monitoring React.useEffect(() => { if (!config.development?.enablePerformanceMetrics) return; const startTime = performance.now(); metricsRef.current.componentRenders++; return () => { const endTime = performance.now(); const renderTime = endTime - startTime; // Update average render time const currentAvg = metricsRef.current.averageRenderTime; const renderCount = metricsRef.current.componentRenders; metricsRef.current.averageRenderTime = (currentAvg * (renderCount - 1) + renderTime) / renderCount; metricsRef.current.lastUpdate = new Date(); if (debugMode && renderTime > 16) { // Slower than 60fps console.debug(`SecureProvider: Slow render detected (${renderTime.toFixed(2)}ms)`); } }; }); // Error boundary effect React.useEffect(() => { const handleError = (event) => { if (onError) { onError(event.error, { phase: "runtime", event }); } }; const handleUnhandledRejection = (event) => { if (onError) { onError(new Error(`Unhandled promise rejection: ${event.reason}`), { phase: "promise-rejection", event }); } }; window.addEventListener("error", handleError); window.addEventListener("unhandledrejection", handleUnhandledRejection); return () => { window.removeEventListener("error", handleError); window.removeEventListener("unhandledrejection", handleUnhandledRejection); }; }, [onError]); // Context value const contextValue = { config, updateConfig, getMetrics, setDebugMode, debugMode, registerComponent, unregisterComponent, getRegisteredComponents, }; // Show fallback while initializing if (!config) { return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: fallback }); } return (jsxRuntimeExports.jsx(SecurityContext.Provider, { value: contextValue, children: children })); }; /** * FortifyJS React Integration - Main Exports * Complete React integration for FortifyJS */ // Hooks // For CommonJS compatibility if (typeof module !== "undefined" && module.exports) { // Named exports module.exports.useSecureState = useSecureState; module.exports.useSecureObject = useSecureObject; module.exports.useStaticSecureObject = useStaticSecureObject; module.exports.useAsyncSecureObject = useAsyncSecureObject; module.exports.SecureProvider = SecureProvider; module.exports.useSecurityContext = useSecurityContext; module.exports.useSecurityConfig = useSecurityConfig; module.exports.useIsSensitiveKey = useIsSensitiveKey; module.exports.useSecurityMetrics = useSecurityMetrics; module.exports.useDebugMode = useDebugMode; module.exports.useComponentRegistration = useComponentRegistration; module.exports.useComponentMetrics = useComponentMetrics; module.exports.DEFAULT_SECURITY_CONFIG = DEFAULT_SECURITY_CONFIG; } exports.DEFAULT_SECURITY_CONFIG = DEFAULT_SECURITY_CONFIG; exports.SecureProvider = SecureProvider; exports.useAsyncSecureObject = useAsyncSecureObject; exports.useComponentMetrics = useComponentMetrics; exports.useComponentRegistration = useComponentRegistration; exports.useDebugMode = useDebugMode; exports.useIsSensitiveKey = useIsSensitiveKey; exports.useSecureObject = useSecureObject; exports.useSecureState = useSecureState; exports.useSecurityConfig = useSecurityConfig; exports.useSecurityContext = useSecurityContext; exports.useSecurityMetrics = useSecurityMetrics; exports.useStaticSecureObject = useStaticSecureObject; //# sourceMappingURL=index.cjs.map