Files
Charon/frontend/src/hooks/useSecurityHeaders.ts
GitHub Actions 8cf762164f feat: implement HTTP Security Headers management (Issue #20)
Add comprehensive security header management system with reusable
profiles, interactive builders, and security scoring.

Features:
- SecurityHeaderProfile model with 11+ header types
- CRUD API with 10 endpoints (/api/v1/security/headers/*)
- Caddy integration for automatic header injection
- 3 built-in presets (Basic, Strict, Paranoid)
- Security score calculator (0-100) with suggestions
- Interactive CSP builder with validation
- Permissions-Policy builder
- Real-time security score preview
- Per-host profile assignment

Headers Supported:
- HSTS with preload support
- Content-Security-Policy with report-only mode
- X-Frame-Options, X-Content-Type-Options
- Referrer-Policy, Permissions-Policy
- Cross-Origin-Opener/Resource/Embedder-Policy
- X-XSS-Protection, Cache-Control security

Implementation:
- Backend: models, handlers, services (85% coverage)
- Frontend: React components, hooks (87.46% coverage)
- Tests: 1,163 total tests passing
- Docs: Comprehensive feature documentation

Closes #20
2025-12-19 18:55:48 +00:00

108 lines
3.3 KiB
TypeScript

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { securityHeadersApi } from '../api/securityHeaders';
import type { CreateProfileRequest, ApplyPresetRequest } from '../api/securityHeaders';
import toast from 'react-hot-toast';
export function useSecurityHeaderProfiles() {
return useQuery({
queryKey: ['securityHeaderProfiles'],
queryFn: securityHeadersApi.listProfiles,
});
}
export function useSecurityHeaderProfile(id: number | string | undefined) {
return useQuery({
queryKey: ['securityHeaderProfile', id],
queryFn: () => securityHeadersApi.getProfile(id!),
enabled: !!id,
});
}
export function useCreateSecurityHeaderProfile() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreateProfileRequest) => securityHeadersApi.createProfile(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['securityHeaderProfiles'] });
toast.success('Security header profile created successfully');
},
onError: (error: Error) => {
toast.error(`Failed to create profile: ${error.message}`);
},
});
}
export function useUpdateSecurityHeaderProfile() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: number; data: Partial<CreateProfileRequest> }) =>
securityHeadersApi.updateProfile(id, data),
onSuccess: (_, variables) => {
queryClient.invalidateQueries({ queryKey: ['securityHeaderProfiles'] });
queryClient.invalidateQueries({ queryKey: ['securityHeaderProfile', variables.id] });
toast.success('Security header profile updated successfully');
},
onError: (error: Error) => {
toast.error(`Failed to update profile: ${error.message}`);
},
});
}
export function useDeleteSecurityHeaderProfile() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: number) => securityHeadersApi.deleteProfile(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['securityHeaderProfiles'] });
toast.success('Security header profile deleted successfully');
},
onError: (error: Error) => {
toast.error(`Failed to delete profile: ${error.message}`);
},
});
}
export function useSecurityHeaderPresets() {
return useQuery({
queryKey: ['securityHeaderPresets'],
queryFn: securityHeadersApi.getPresets,
});
}
export function useApplySecurityHeaderPreset() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: ApplyPresetRequest) => securityHeadersApi.applyPreset(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['securityHeaderProfiles'] });
toast.success('Preset applied successfully');
},
onError: (error: Error) => {
toast.error(`Failed to apply preset: ${error.message}`);
},
});
}
export function useCalculateSecurityScore() {
return useMutation({
mutationFn: (config: Partial<CreateProfileRequest>) => securityHeadersApi.calculateScore(config),
});
}
export function useValidateCSP() {
return useMutation({
mutationFn: (csp: string) => securityHeadersApi.validateCSP(csp),
});
}
export function useBuildCSP() {
return useMutation({
mutationFn: (directives: { directive: string; values: string[] }[]) =>
securityHeadersApi.buildCSP(directives),
});
}