diff --git a/actions/services.ts b/actions/services.ts new file mode 100644 index 0000000000..aeb9d7de07 --- /dev/null +++ b/actions/services.ts @@ -0,0 +1,39 @@ +"use server"; + +import { revalidatePath } from "next/cache"; +import { redirect } from "next/navigation"; + +import { parseStringify } from "@/lib"; + +export const getService = async ({ page = 1 }) => { + if (isNaN(Number(page)) || page < 1) redirect("/services"); + const keyServer = process.env.LOCAL_SITE_URL; + + try { + const services = await fetch( + `${keyServer}/api/services?page%5Bnumber%5D=${page}`, + ); + const data = await services.json(); + const parsedData = parseStringify(data); + revalidatePath("/services"); + return parsedData; + } catch (error) { + console.error("Error fetching services:", error); + return undefined; + } +}; + +export const getErrorMessage = (error: unknown): string => { + let message: string; + + if (error instanceof Error) { + message = error.message; + } else if (error && typeof error === "object" && "message" in error) { + message = String(error.message); + } else if (typeof error === "string") { + message = error; + } else { + message = "Wops! Something when wrong."; + } + return message; +}; diff --git a/app/(prowler)/providers/page.tsx b/app/(prowler)/providers/page.tsx index 2c79e94c79..780d736710 100644 --- a/app/(prowler)/providers/page.tsx +++ b/app/(prowler)/providers/page.tsx @@ -16,7 +16,7 @@ export default async function Providers({ searchParams }: searchParamsProps) { return ( <>
- +
diff --git a/app/(prowler)/services/page.tsx b/app/(prowler)/services/page.tsx index 1564675110..e9af97846a 100644 --- a/app/(prowler)/services/page.tsx +++ b/app/(prowler)/services/page.tsx @@ -1,73 +1,47 @@ -import { FilterControls } from "@/components/filters"; -import { - AmazonEC2Icon, - AmazonEMRIcon, - AmazonGuardDutyIcon, - AmazonInspectorIcon, - AmazonMacieIcon, - AmazonRDSIcon, - AmazonRoute53Icon, - AmazonS3Icon, - AmazonSNSIcon, - AmazonVPCIcon, - AWSAccountIcon, - AWSAthenaIcon, - AWSCertificateManagerIcon, - AWSCloudFormationIcon, - AWSCloudTrailIcon, - AWSCloudWatchIcon, - AWSConfigIcon, - AWSDatabaseMigrationServiceIcon, - AWSGlueIcon, - AWSIAMIcon, - AWSLambdaIcon, - AWSNetworkFirewallIcon, - AWSOrganizationsIcon, - AWSResourceExplorerIcon, - AWSSecurityHubIcon, - AWSSystemsManagerIncidentManagerIcon, - AWSTrustedAdvisorIcon, - IAMAccessAnalyzerIcon, -} from "@/components/icons"; -import { Header } from "@/components/ui"; +import { Spacer } from "@nextui-org/react"; +import { redirect } from "next/navigation"; +import { Suspense } from "react"; -export default function Services() { +import { getService } from "@/actions/services"; +import { FilterControls } from "@/components/filters"; +import { SkeletonTableProvider } from "@/components/providers"; +import { CardService } from "@/components/services"; +import { Header } from "@/components/ui"; +import { searchParamsProps } from "@/types"; + +export default async function Services({ searchParams }: searchParamsProps) { return ( <>
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + }> + + ); } + +const SSRServiceGrid = async ({ searchParams }: searchParamsProps) => { + const page = searchParams.page ? parseInt(searchParams.page) : 1; + const servicesData = await getService({ page }); + const [services] = await Promise.all([servicesData]); + + if (services?.errors) redirect("/services"); + + return ( +
+ {services.services?.data.map((service: any) => ( + + ))} +
+ ); +}; diff --git a/app/api/services/route.ts b/app/api/services/route.ts new file mode 100644 index 0000000000..dbd490c239 --- /dev/null +++ b/app/api/services/route.ts @@ -0,0 +1,10 @@ +import { NextResponse } from "next/server"; + +import data from "../../../dataServices.json"; + +export async function GET() { + // Simulate fetching data with a delay + await new Promise((resolve) => setTimeout(resolve, 2000)); + + return NextResponse.json({ services: data }); +} diff --git a/components/icons/Icons.tsx b/components/icons/Icons.tsx index a929e7f750..6024849b2d 100644 --- a/components/icons/Icons.tsx +++ b/components/icons/Icons.tsx @@ -440,3 +440,47 @@ export const AlertIcon: React.FC = ({ ); + +export const NotificationIcon: React.FC = ({ + size = 24, + width, + height, + ...props +}) => ( + + + +); + +export const SuccessIcon: React.FC = ({ + size = 24, + width, + height, + ...props +}) => ( + + + +); diff --git a/components/icons/services/IconServices.tsx b/components/icons/services/IconServices.tsx index 739d21e9a9..2fd943604e 100644 --- a/components/icons/services/IconServices.tsx +++ b/components/icons/services/IconServices.tsx @@ -858,3 +858,66 @@ export const AmazonVPCIcon: React.FC = ({ ); + +export const getAWSIcon = (serviceAlias: string) => { + switch (serviceAlias) { + case "Amazon EC2": + return ; + case "Amazon EMR": + return ; + case "Amazon GuardDuty": + return ; + case "Amazon Inspector": + return ; + case "Amazon Macie": + return ; + case "Amazon RDS": + return ; + case "Amazon Route 53": + return ; + case "Amazon S3": + return ; + case "Amazon SNS": + return ; + case "Amazon VPC": + return ; + case "AWS Account": + return ; + case "AWS Athena": + return ; + case "AWS Certificate Manager": + return ; + case "AWS CloudFormation": + return ; + case "AWS CloudTrail": + return ; + case "AWS CloudWatch": + return ; + case "AWS Config": + return ; + case "AWS Database Migration Service": + return ; + case "AWS Glue": + return ; + case "AWS IAM": + return ; + case "AWS Lambda": + return ; + case "AWS Network Firewall": + return ; + case "AWS Organizations": + return ; + case "AWS Resource Explorer": + return ; + case "AWS Security Hub": + return ; + case "AWS Systems Manager Incident Manager": + return ; + case "AWS Trusted Advisor": + return ; + case "IAM Access Analyzer": + return ; + default: + return null; + } +}; diff --git a/components/services/CardService.tsx b/components/services/CardService.tsx new file mode 100644 index 0000000000..eaae8dc450 --- /dev/null +++ b/components/services/CardService.tsx @@ -0,0 +1,45 @@ +import { Card, CardBody, Chip } from "@nextui-org/react"; + +import { getAWSIcon, NotificationIcon, SuccessIcon } from "../icons"; + +interface CardServiceProps { + fidingsFailed: number; + serviceAlias: string; +} +export const CardService: React.FC = ({ + fidingsFailed, + serviceAlias, +}) => { + return ( + + + {getAWSIcon(serviceAlias)} +
+

{serviceAlias}

+ + {fidingsFailed > 0 + ? `${fidingsFailed} Failed Findings` + : "All findings passed"} + +
+ + 0 ? ( + + ) : ( + + ) + } + color={fidingsFailed > 0 ? "danger" : "success"} + radius="full" + size="md" + > + {fidingsFailed > 0 ? fidingsFailed : "All passed"} + +
+
+ ); +}; diff --git a/components/services/index.ts b/components/services/index.ts index e69de29bb2..ea59ab0d9b 100644 --- a/components/services/index.ts +++ b/components/services/index.ts @@ -0,0 +1 @@ +export * from "./CardService"; diff --git a/dataServices.json b/dataServices.json new file mode 100644 index 0000000000..cfda95d520 --- /dev/null +++ b/dataServices.json @@ -0,0 +1,494 @@ +{ + "links": { + "first": "http://localhost:8080/api/v1/services?page%5Bnumber%5D=1", + "last": "http://localhost:8080/api/v1/services?page%5Bnumber%5D=1", + "next": null, + "prev": null + }, + "data": [ + { + "type": "Service", + "id": "001", + "attributes": { + "inserted_at": "2024-08-14T10:00:00.000000Z", + "updated_at": "2024-08-14T10:00:00.000000Z", + "provider": "aws", + "provider_id": "001", + "alias": "Amazon EC2", + "regions": ["us-east-1", "us-east-2"], + "findings": { + "failed": 3, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "002", + "attributes": { + "inserted_at": "2024-08-14T10:01:00.000000Z", + "updated_at": "2024-08-14T10:01:00.000000Z", + "provider": "aws", + "provider_id": "002", + "alias": "Amazon EMR", + "regions": ["us-west-1", "us-west-2"], + "findings": { + "failed": 0, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "003", + "attributes": { + "inserted_at": "2024-08-14T10:02:00.000000Z", + "updated_at": "2024-08-14T10:02:00.000000Z", + "provider": "aws", + "provider_id": "003", + "alias": "Amazon GuardDuty", + "regions": ["eu-west-1", "eu-west-2"], + "findings": { + "failed": 5, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "004", + "attributes": { + "inserted_at": "2024-08-14T10:03:00.000000Z", + "updated_at": "2024-08-14T10:03:00.000000Z", + "provider": "aws", + "provider_id": "004", + "alias": "Amazon Inspector", + "regions": ["ap-southeast-1", "ap-southeast-2"], + "findings": { + "failed": 0, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "005", + "attributes": { + "inserted_at": "2024-08-14T10:04:00.000000Z", + "updated_at": "2024-08-14T10:04:00.000000Z", + "provider": "aws", + "provider_id": "005", + "alias": "Amazon Macie", + "regions": ["eu-north-1", "eu-north-2"], + "findings": { + "failed": 2, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "006", + "attributes": { + "inserted_at": "2024-08-14T10:05:00.000000Z", + "updated_at": "2024-08-14T10:05:00.000000Z", + "provider": "aws", + "provider_id": "006", + "alias": "Amazon RDS", + "regions": ["sa-east-1", "sa-east-2"], + "findings": { + "failed": 0, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "007", + "attributes": { + "inserted_at": "2024-08-14T10:06:00.000000Z", + "updated_at": "2024-08-14T10:06:00.000000Z", + "provider": "aws", + "provider_id": "007", + "alias": "Amazon Route 53", + "regions": ["af-south-1", "af-south-2"], + "findings": { + "failed": 1, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "008", + "attributes": { + "inserted_at": "2024-08-14T10:07:00.000000Z", + "updated_at": "2024-08-14T10:07:00.000000Z", + "provider": "aws", + "provider_id": "008", + "alias": "Amazon S3", + "regions": ["us-east-1", "us-west-1"], + "findings": { + "failed": 3, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "009", + "attributes": { + "inserted_at": "2024-08-14T10:08:00.000000Z", + "updated_at": "2024-08-14T10:08:00.000000Z", + "provider": "aws", + "provider_id": "009", + "alias": "Amazon SNS", + "regions": ["eu-central-1", "eu-central-2"], + "findings": { + "failed": 0, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "010", + "attributes": { + "inserted_at": "2024-08-14T10:09:00.000000Z", + "updated_at": "2024-08-14T10:09:00.000000Z", + "provider": "aws", + "provider_id": "010", + "alias": "Amazon VPC", + "regions": ["us-west-1", "us-west-2"], + "findings": { + "failed": 4, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "011", + "attributes": { + "inserted_at": "2024-08-14T10:10:00.000000Z", + "updated_at": "2024-08-14T10:10:00.000000Z", + "provider": "aws", + "provider_id": "011", + "alias": "AWS Account", + "regions": ["eu-west-1", "eu-west-3"], + "findings": { + "failed": 0, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "012", + "attributes": { + "inserted_at": "2024-08-14T10:11:00.000000Z", + "updated_at": "2024-08-14T10:11:00.000000Z", + "provider": "aws", + "provider_id": "012", + "alias": "AWS Athena", + "regions": ["us-east-1", "us-east-2"], + "findings": { + "failed": 5, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "013", + "attributes": { + "inserted_at": "2024-08-14T10:12:00.000000Z", + "updated_at": "2024-08-14T10:12:00.000000Z", + "provider": "aws", + "provider_id": "013", + "alias": "AWS Certificate Manager", + "regions": ["us-west-1", "us-west-2"], + "findings": { + "failed": 1, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "014", + "attributes": { + "inserted_at": "2024-08-14T10:13:00.000000Z", + "updated_at": "2024-08-14T10:13:00.000000Z", + "provider": "aws", + "provider_id": "014", + "alias": "AWS CloudFormation", + "regions": ["eu-central-1", "eu-central-2"], + "findings": { + "failed": 0, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "015", + "attributes": { + "inserted_at": "2024-08-14T10:14:00.000000Z", + "updated_at": "2024-08-14T10:14:00.000000Z", + "provider": "aws", + "provider_id": "015", + "alias": "AWS CloudTrail", + "regions": ["us-east-1", "us-east-2"], + "findings": { + "failed": 4, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "016", + "attributes": { + "inserted_at": "2024-08-14T10:15:00.000000Z", + "updated_at": "2024-08-14T10:15:00.000000Z", + "provider": "aws", + "provider_id": "016", + "alias": "AWS CloudWatch", + "regions": ["us-west-1", "us-west-2"], + "findings": { + "failed": 2, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "017", + "attributes": { + "inserted_at": "2024-08-14T10:16:00.000000Z", + "updated_at": "2024-08-14T10:16:00.000000Z", + "provider": "aws", + "provider_id": "017", + "alias": "AWS Config", + "regions": ["eu-west-1", "eu-west-3"], + "findings": { + "failed": 0, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "018", + "attributes": { + "inserted_at": "2024-08-14T10:17:00.000000Z", + "updated_at": "2024-08-14T10:17:00.000000Z", + "provider": "aws", + "provider_id": "018", + "alias": "AWS Database Migration Service", + "regions": ["us-east-1", "us-east-2"], + "findings": { + "failed": 5, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "019", + "attributes": { + "inserted_at": "2024-08-14T10:18:00.000000Z", + "updated_at": "2024-08-14T10:18:00.000000Z", + "provider": "aws", + "provider_id": "019", + "alias": "AWS Glue", + "regions": ["us-west-1", "us-west-2"], + "findings": { + "failed": 1, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "020", + "attributes": { + "inserted_at": "2024-08-14T10:19:00.000000Z", + "updated_at": "2024-08-14T10:19:00.000000Z", + "provider": "aws", + "provider_id": "020", + "alias": "AWS IAM", + "regions": ["eu-central-1", "eu-central-2"], + "findings": { + "failed": 0, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "021", + "attributes": { + "inserted_at": "2024-08-14T10:20:00.000000Z", + "updated_at": "2024-08-14T10:20:00.000000Z", + "provider": "aws", + "provider_id": "021", + "alias": "AWS Lambda", + "regions": ["us-east-1", "us-east-2"], + "findings": { + "failed": 4, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "022", + "attributes": { + "inserted_at": "2024-08-14T10:21:00.000000Z", + "updated_at": "2024-08-14T10:21:00.000000Z", + "provider": "aws", + "provider_id": "022", + "alias": "AWS Network Firewall", + "regions": ["us-west-1", "us-west-2"], + "findings": { + "failed": 2, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "023", + "attributes": { + "inserted_at": "2024-08-14T10:22:00.000000Z", + "updated_at": "2024-08-14T10:22:00.000000Z", + "provider": "aws", + "provider_id": "023", + "alias": "AWS Organizations", + "regions": ["eu-west-1", "eu-west-3"], + "findings": { + "failed": 0, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "024", + "attributes": { + "inserted_at": "2024-08-14T10:23:00.000000Z", + "updated_at": "2024-08-14T10:23:00.000000Z", + "provider": "aws", + "provider_id": "024", + "alias": "AWS Resource Explorer", + "regions": ["us-east-1", "us-east-2"], + "findings": { + "failed": 3, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "025", + "attributes": { + "inserted_at": "2024-08-14T10:24:00.000000Z", + "updated_at": "2024-08-14T10:24:00.000000Z", + "provider": "aws", + "provider_id": "025", + "alias": "AWS Security Hub", + "regions": ["us-west-1", "us-west-2"], + "findings": { + "failed": 5, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "026", + "attributes": { + "inserted_at": "2024-08-14T10:25:00.000000Z", + "updated_at": "2024-08-14T10:25:00.000000Z", + "provider": "aws", + "provider_id": "026", + "alias": "AWS Systems Manager Incident Manager", + "regions": ["eu-west-1", "eu-west-3"], + "findings": { + "failed": 0, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "027", + "attributes": { + "inserted_at": "2024-08-14T10:26:00.000000Z", + "updated_at": "2024-08-14T10:26:00.000000Z", + "provider": "aws", + "provider_id": "027", + "alias": "AWS Trusted Advisor", + "regions": ["us-east-1", "us-east-2"], + "findings": { + "failed": 2, + "last_checked_at": null + }, + "scanner_args": {} + } + }, + { + "type": "Service", + "id": "028", + "attributes": { + "inserted_at": "2024-08-14T10:27:00.000000Z", + "updated_at": "2024-08-14T10:27:00.000000Z", + "provider": "aws", + "provider_id": "028", + "alias": "IAM Access Analyzer", + "regions": ["eu-west-1", "eu-west-3"], + "findings": { + "failed": 0, + "last_checked_at": null + }, + "scanner_args": {} + } + } + ], + "meta": { + "pagination": { + "page": 1, + "pages": 1, + "count": 28 + }, + "version": "v1" + } +}