mirror of
https://github.com/kjanat/livedash-node.git
synced 2026-01-16 12:12:09 +01:00
fix: improve admin security and modal accessibility
- Replace Card-based modal with proper Dialog component in SecurityAlertsTable for better accessibility - Add missing admin role check to threat-analysis endpoint for proper authorization - Implement ARIA attributes, focus management, and semantic structure - Ensure consistent admin security patterns across endpoints
This commit is contained in:
@ -29,7 +29,7 @@ export async function POST(request: NextRequest) {
|
|||||||
try {
|
try {
|
||||||
const session = await getServerSession(authOptions);
|
const session = await getServerSession(authOptions);
|
||||||
|
|
||||||
if (!session?.user || !session.user.isPlatformUser) {
|
if (!session?.user || session.user.role !== "ADMIN") {
|
||||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,15 @@ import { AlertTriangle, CheckCircle, Eye, EyeOff } from "lucide-react";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
@ -196,32 +204,32 @@ export function SecurityAlertsTable({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Alert Details Modal */}
|
{/* Alert Details Modal */}
|
||||||
{selectedAlert && (
|
<Dialog
|
||||||
<Card className="fixed inset-0 z-50 bg-black/50 flex items-center justify-center p-4">
|
open={!!selectedAlert}
|
||||||
<Card className="max-w-2xl w-full max-h-[80vh] overflow-auto">
|
onOpenChange={() => setSelectedAlert(null)}
|
||||||
<CardHeader>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<DialogContent className="max-w-2xl max-h-[80vh] overflow-auto">
|
||||||
<div className="space-y-2">
|
<DialogHeader>
|
||||||
<CardTitle>{selectedAlert.title}</CardTitle>
|
<DialogTitle className="flex items-center gap-2">
|
||||||
|
{selectedAlert?.title}
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Badge variant={getSeverityColor(selectedAlert.severity)}>
|
<Badge
|
||||||
{selectedAlert.severity}
|
variant={getSeverityColor(selectedAlert?.severity || "")}
|
||||||
|
>
|
||||||
|
{selectedAlert?.severity}
|
||||||
</Badge>
|
</Badge>
|
||||||
<Badge variant="outline">
|
<Badge variant="outline">
|
||||||
{formatAlertType(selectedAlert.type)}
|
{formatAlertType(selectedAlert?.type || "")}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</DialogTitle>
|
||||||
<Button
|
<DialogDescription>
|
||||||
variant="outline"
|
Security alert details and context information
|
||||||
size="sm"
|
</DialogDescription>
|
||||||
onClick={() => setSelectedAlert(null)}
|
</DialogHeader>
|
||||||
>
|
|
||||||
Close
|
{selectedAlert && (
|
||||||
</Button>
|
<div className="space-y-4">
|
||||||
</div>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="space-y-4">
|
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-medium mb-2">Description</h4>
|
<h4 className="font-medium mb-2">Description</h4>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
@ -249,12 +257,15 @@ export function SecurityAlertsTable({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="flex items-center justify-between pt-4 border-t">
|
<DialogFooter className="flex items-center justify-between pt-4 border-t">
|
||||||
<span className="text-sm text-muted-foreground">
|
<span className="text-sm text-muted-foreground">
|
||||||
{formatTimestamp(selectedAlert.timestamp)}
|
{selectedAlert && formatTimestamp(selectedAlert.timestamp)}
|
||||||
</span>
|
</span>
|
||||||
{!selectedAlert.acknowledged && (
|
<div className="flex gap-2">
|
||||||
|
{selectedAlert && !selectedAlert.acknowledged && (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onAcknowledge(selectedAlert.id);
|
onAcknowledge(selectedAlert.id);
|
||||||
@ -265,10 +276,9 @@ export function SecurityAlertsTable({
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</DialogFooter>
|
||||||
</Card>
|
</DialogContent>
|
||||||
</Card>
|
</Dialog>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user