import * as plugins from '../plugins.js'; import * as interfaces from '../../ts_interfaces/index.js'; import { appState } from './shared.js'; import { getActionContext } from './login.js'; import { runBackgroundRefresh } from './shared.js'; export interface ISecurityPolicyState { rules: interfaces.data.ISecurityBlockRule[]; ipIntelligence: interfaces.data.IIpIntelligenceRecord[]; compiledPolicy: interfaces.data.ISecurityCompiledPolicy | null; auditEvents: interfaces.data.ISecurityPolicyAuditEvent[]; isLoading: boolean; error: string | null; lastUpdated: number; } export const securityPolicyStatePart = await appState.getStatePart( 'securityPolicy', { rules: [], ipIntelligence: [], compiledPolicy: null, auditEvents: [], isLoading: false, error: null, lastUpdated: 0, }, 'soft', ); function refreshSecurityIpIntelligence(identity: interfaces.data.IIdentity): void { runBackgroundRefresh('securityIpIntelligence', 'Security IP intelligence refresh failed:', async () => { const intelligenceRequest = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_ListIpIntelligence >('/typedrequest', 'listIpIntelligence'); const intelligenceResponse = await intelligenceRequest.fire({ identity, limit: 500, }); securityPolicyStatePart.setState({ ...securityPolicyStatePart.getState()!, ipIntelligence: intelligenceResponse.records || [], }); }); } // Security Policy Actions // ============================================================================ export const fetchSecurityPolicyAction = securityPolicyStatePart.createAction( async (statePartArg): Promise => { const context = getActionContext(); const currentState = statePartArg.getState()!; if (!context.identity) return currentState; try { const rulesRequest = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_ListSecurityBlockRules >('/typedrequest', 'listSecurityBlockRules'); const compiledPolicyRequest = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_GetCompiledSecurityPolicy >('/typedrequest', 'getCompiledSecurityPolicy'); const auditRequest = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_ListSecurityPolicyAudit >('/typedrequest', 'listSecurityPolicyAudit'); const [rulesResponse, compiledPolicyResponse, auditResponse] = await Promise.all([ rulesRequest.fire({ identity: context.identity }), compiledPolicyRequest.fire({ identity: context.identity }), auditRequest.fire({ identity: context.identity, limit: 100 }), ]); refreshSecurityIpIntelligence(context.identity); return { rules: rulesResponse.rules || [], ipIntelligence: currentState.ipIntelligence, compiledPolicy: compiledPolicyResponse.policy, auditEvents: auditResponse.events || [], isLoading: false, error: null, lastUpdated: Date.now(), }; } catch (error: unknown) { return { ...currentState, isLoading: false, error: error instanceof Error ? error.message : 'Failed to fetch security policy', }; } }, ); export const createSecurityBlockRuleAction = securityPolicyStatePart.createAction<{ type: interfaces.data.TSecurityBlockRuleType; value: string; matchMode?: interfaces.data.TSecurityBlockRuleMatchMode; reason?: string; enabled?: boolean; }>(async (statePartArg, dataArg, actionContext): Promise => { const context = getActionContext(); const currentState = statePartArg.getState()!; if (!context.identity) return currentState; try { const request = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_CreateSecurityBlockRule >('/typedrequest', 'createSecurityBlockRule'); const response = await request.fire({ identity: context.identity, type: dataArg.type, value: dataArg.value, matchMode: dataArg.matchMode, reason: dataArg.reason, enabled: dataArg.enabled, }); if (!response.success) { return { ...currentState, error: response.message || 'Failed to create security block rule' }; } return await actionContext!.dispatch(fetchSecurityPolicyAction, null); } catch (error: unknown) { return { ...currentState, error: error instanceof Error ? error.message : 'Failed to create security block rule', }; } }); export const updateSecurityBlockRuleAction = securityPolicyStatePart.createAction<{ id: string; value?: string; matchMode?: interfaces.data.TSecurityBlockRuleMatchMode; reason?: string; enabled?: boolean; }>(async (statePartArg, dataArg, actionContext): Promise => { const context = getActionContext(); const currentState = statePartArg.getState()!; if (!context.identity) return currentState; try { const request = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_UpdateSecurityBlockRule >('/typedrequest', 'updateSecurityBlockRule'); const response = await request.fire({ identity: context.identity, id: dataArg.id, value: dataArg.value, matchMode: dataArg.matchMode, reason: dataArg.reason, enabled: dataArg.enabled, }); if (!response.success) { return { ...currentState, error: response.message || 'Failed to update security block rule' }; } return await actionContext!.dispatch(fetchSecurityPolicyAction, null); } catch (error: unknown) { return { ...currentState, error: error instanceof Error ? error.message : 'Failed to update security block rule', }; } }); export const deleteSecurityBlockRuleAction = securityPolicyStatePart.createAction( async (statePartArg, ruleId, actionContext): Promise => { const context = getActionContext(); const currentState = statePartArg.getState()!; if (!context.identity) return currentState; try { const request = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_DeleteSecurityBlockRule >('/typedrequest', 'deleteSecurityBlockRule'); const response = await request.fire({ identity: context.identity, id: ruleId }); if (!response.success) { return { ...currentState, error: response.message || 'Failed to delete security block rule' }; } return await actionContext!.dispatch(fetchSecurityPolicyAction, null); } catch (error: unknown) { return { ...currentState, error: error instanceof Error ? error.message : 'Failed to delete security block rule', }; } }, ); export const refreshIpIntelligenceAction = securityPolicyStatePart.createAction( async (statePartArg, ipAddress, actionContext): Promise => { const context = getActionContext(); const currentState = statePartArg.getState()!; if (!context.identity) return currentState; try { const request = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_RefreshIpIntelligence >('/typedrequest', 'refreshIpIntelligence'); const response = await request.fire({ identity: context.identity, ipAddress }); if (!response.success) { return { ...currentState, error: response.message || 'Failed to refresh IP intelligence' }; } const refreshedState = await actionContext!.dispatch(fetchSecurityPolicyAction, null); if (!response.record) return refreshedState; return { ...refreshedState, ipIntelligence: [ response.record, ...refreshedState.ipIntelligence.filter((record) => record.ipAddress !== response.record!.ipAddress), ], }; } catch (error: unknown) { return { ...currentState, error: error instanceof Error ? error.message : 'Failed to refresh IP intelligence', }; } }, ); // ============================================================================