diff --git a/backend/src/xfd_django/xfd_api/views.py b/backend/src/xfd_django/xfd_api/views.py index 7e87fa44..97dc179e 100644 --- a/backend/src/xfd_django/xfd_api/views.py +++ b/backend/src/xfd_django/xfd_api/views.py @@ -116,20 +116,8 @@ async def get_redis_client(request: Request): return request.app.state.redis -# Healthcheck endpoint -@api_router.get("/healthcheck", tags=["Testing"]) -async def healthcheck(): - """ - Healthcheck endpoint. - - Returns: - dict: A dictionary containing the health status of the application. - """ - return {"status": "ok"} - - # ======================================== -# Proxy Endpoints +# Analytics # ======================================== @@ -174,7 +162,7 @@ async def matomo_proxy( @api_router.api_route( "/pe/{path:path}", dependencies=[Depends(get_current_active_user)], - tags=["P&E Proxy"], + tags=["Analytics"], ) async def pe_proxy( path: str, request: Request, current_user: User = Depends(get_current_active_user) @@ -188,6 +176,63 @@ async def pe_proxy( return await proxy.proxy_request(request, os.getenv("PE_API_URL", ""), path) +# ======================================== +# API Keys +# ======================================== + + +# POST +@api_router.post("/api-keys", response_model=ApiKeySchema, tags=["API Keys"]) +async def create_api_key(current_user: User = Depends(get_current_active_user)): + """Create api key.""" + return api_key_methods.post(current_user) + + +# DELETE +@api_router.delete("/api-keys/{id}", tags=["API Keys"]) +async def delete_api_key( + id: str, current_user: User = Depends(get_current_active_user) +): + """Delete api key by id.""" + return api_key_methods.delete(id, current_user) + + +# ======================================== +# Auth +# ======================================== + + +# Okta Callback +@api_router.post("/auth/okta-callback", tags=["Auth"]) +async def okta_callback(request: Request): + """Handle Okta Callback.""" + return await auth_methods.handle_okta_callback(request) + + +# Login +@api_router.get("/login", tags=["Auth"]) +async def login_route(): + """Handle V1 Login.""" + return login() + + +# V1 Callback +@api_router.post("/auth/callback", tags=["Auth"]) +async def callback_route(request: Request): + """Handle V1 Callback.""" + body = await request.json() + try: + user_info = callback(body) + return user_info + except Exception as error: + raise HTTPException(status_code=400, detail=str(error)) + + +# ======================================== +# CPEs +# ======================================== + + @api_router.get( "/cpes/{cpe_id}", # dependencies=[Depends(get_current_active_user)], @@ -203,6 +248,11 @@ async def call_get_cpes_by_id(cpe_id): return get_cpes_by_id(cpe_id) +# ======================================== +# CVEs +# ======================================== + + @api_router.get( "/cves/{cve_id}", # dependencies=[Depends(get_current_active_user)], @@ -233,6 +283,11 @@ async def call_get_cves_by_name(cve_name): return get_cves_by_name(cve_name) +# ======================================== +# Domains +# ======================================== + + @api_router.post( "/domain/search", dependencies=[Depends(get_current_active_user)], @@ -275,302 +330,293 @@ async def call_get_domain_by_id(domain_id: str): return get_domain_by_id(domain_id) +# ======================================== +# Notifications +# ======================================== + + +# POST @api_router.post( - "/vulnerabilities/search", - dependencies=[Depends(get_current_active_user)], - response_model=List[VulnerabilitySchema], - tags=["Vulnerabilities"], + "/notifications", response_model=NotificationSchema, tags=["Notifications"] ) -async def call_search_vulnerabilities( - vulnerability_search: VulnerabilitySearch, - current_user: User = Depends(get_current_active_user), -): - try: - return search_vulnerabilities(vulnerability_search, current_user) - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) +async def create_notification(current_user: User = Depends(get_current_active_user)): + """Create notification key.""" + # return notification_handler.post(current_user) + return [] -@api_router.post("/vulnerabilities/export", tags=["Vulnerabilities"]) -async def export_vulnerabilities(): - try: - pass - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) +# DELETE +@api_router.delete( + "/notifications/{id}", response_model=NotificationSchema, tags=["Notifications"] +) +async def delete_notification( + id: str, current_user: User = Depends(get_current_active_user) +): + """Delete notification by id.""" + return notification_methods.delete(id, current_user) +# GET ALL: Doesn't require authentication @api_router.get( - "/vulnerabilities/{vulnerabilityId}", - dependencies=[Depends(get_current_active_user)], - response_model=VulnerabilitySchema, - tags=["Vulnerabilities"], + "/notifications", response_model=List[NotificationSchema], tags=["Notifications"] ) -async def call_get_vulnerability_by_id(vuln_id): - """ - Get vulnerability by id. - Returns: - object: a single Vulnerability object. - """ - return get_vulnerability_by_id(vuln_id) +async def get_all_notifications(): + """Get all notifications.""" + return notification_methods.get_all() -@api_router.put( - "/vulnerabilities/{vulnerabilityId}", - dependencies=[Depends(get_current_active_user)], - response_model=VulnerabilitySchema, - tags=["Vulnerabilities"], +# GET BY ID +@api_router.get( + "/notifications/{id}", response_model=NotificationSchema, tags=["Notifications"] ) -async def call_update_vulnerability( - vuln_id, - data: VulnerabilitySchema, - current_user: User = Depends(get_current_active_user), +async def get_notification( + id: str, current_user: User = Depends(get_current_active_user) ): - """ - Update vulnerability by id. - - Returns: - object: a single vulnerability object that has been modified. - """ - return update_vulnerability(vuln_id, data, current_user) - - -# ======================================== -# Auth Endpoints -# ======================================== - - -# Okta Callback -@api_router.post("/auth/okta-callback", tags=["Auth"]) -async def okta_callback(request: Request): - """Handle Okta Callback.""" - return await auth_methods.handle_okta_callback(request) + """Get notification by id.""" + return notification_methods.get_by_id(id, current_user) -# Login -@api_router.get("/login", tags=["Auth"]) -async def login_route(): - """Handle V1 Login.""" - return login() +# UPDATE BY ID +@api_router.put("/notifications/{id}", tags=["Notifications"]) +async def update_notification( + id: str, current_user: User = Depends(get_current_active_user) +): + """Update notification key by id.""" + return notification_methods.delete(id, current_user) -# V1 Callback -@api_router.post("/auth/callback", tags=["Auth"]) -async def callback_route(request: Request): - """Handle V1 Callback.""" - body = await request.json() - try: - user_info = callback(body) - return user_info - except Exception as error: - raise HTTPException(status_code=400, detail=str(error)) +# GET 508 Banner: Doesn't require authentication +@api_router.get("/notifications/508-banner", tags=["Notifications"]) +async def get_508_banner(): + """Get notification by id.""" + return notification_methods.get_508_banner() # ======================================== -# User Endpoints +# Organizations # ======================================== -@api_router.post( - "/users/me/acceptTerms", - response_model=UserSchema, +@api_router.get( + "/organizations", dependencies=[Depends(get_current_active_user)], - tags=["Users"], + response_model=List[OrganizationSchema.GetOrganizationSchema], + tags=["Organizations"], ) -async def call_accept_terms( - version_data: VersionModel, current_user: User = Depends(get_current_active_user) -): - """Accept the latest terms of service.""" - - return accept_terms(version_data, current_user) +async def list_organizations(current_user: User = Depends(get_current_active_user)): + """Retrieve a list of all organizations.""" + return organization.list_organizations(current_user) -@api_router.get("/users/me", tags=["Users"]) -async def read_users_me(current_user: User = Depends(get_current_active_user)): - return get_me(current_user) +@api_router.get( + "/organizations/tags", + dependencies=[Depends(get_current_active_user)], + response_model=List[OrganizationSchema.GetTagSchema], + tags=["Organizations"], +) +async def get_organization_tags(current_user: User = Depends(get_current_active_user)): + """Retrieve a list of organization tags.""" + return organization.get_tags(current_user) -@api_router.delete( - "/users/{userId}", - response_model=OrganizationSchema.GenericMessageResponseModel, +@api_router.get( + "/organizations/{organization_id}", dependencies=[Depends(get_current_active_user)], - tags=["Users"], + response_model=OrganizationSchema.GetSingleOrganizationSchema, + tags=["Organizations"], ) -async def call_delete_user( - userId: str, current_user: User = Depends(get_current_active_user) +async def get_organization( + organization_id: str, current_user: User = Depends(get_current_active_user) ): - """Delete user.""" - return delete_user(userId, current_user) + """Retrieve an organization by its ID.""" + return organization.get_organization(organization_id, current_user) @api_router.get( - "/users", - response_model=List[UserResponseV2], + "/organizations/state/{state}", dependencies=[Depends(get_current_active_user)], - tags=["Users"], + response_model=List[OrganizationSchema.GetOrganizationSchema], + tags=["Organizations"], ) -async def call_get_users(current_user: User = Depends(get_current_active_user)): - """Get all users.""" - return get_users(current_user) +async def get_organizations_by_state( + state: str, current_user: User = Depends(get_current_active_user) +): + """Retrieve organizations by state.""" + return organization.get_by_state(state, current_user) @api_router.get( - "/users/regionId/{regionId}", - response_model=List[UserSchema], + "/organizations/regionId/{region_id}", dependencies=[Depends(get_current_active_user)], - tags=["Users"], + response_model=List[OrganizationSchema.GetOrganizationSchema], + tags=["Organizations"], ) -async def call_get_users_by_region_id( - regionId, current_user: User = Depends(get_current_active_user) +async def get_organizations_by_region( + region_id: str, current_user: User = Depends(get_current_active_user) ): - """ - Call get_users_by_region_id() - Args: - request : The HTTP request containing query parameters. - - Raises: - HTTPException: If the user is not authorized or no users are found. - - Returns: - List[User]: A list of users matching the filter criteria. - """ - return get_users_by_region_id(regionId, current_user) + """Retrieve organizations by region ID.""" + return organization.get_by_region(region_id, current_user) @api_router.get( - "/users/state/{state}", - response_model=List[UserSchema], + "/regions", dependencies=[Depends(get_current_active_user)], - tags=["Users"], + response_model=List[OrganizationSchema.RegionSchema], + tags=["Regions"], ) -async def call_get_users_by_state( - state, current_user: User = Depends(get_current_active_user) -): - """ - Call get_users_by_state() - Args: - request : The HTTP request containing query parameters. +async def list_regions(current_user: User = Depends(get_current_active_user)): + """Retrieve a list of all regions.""" + return organization.get_all_regions(current_user) - Raises: - HTTPException: If the user is not authorized or no users are found. - Returns: - List[User]: A list of users matching the filter criteria. - """ - return get_users_by_state(state, current_user) +@api_router.post( + "/organizations", + dependencies=[Depends(get_current_active_user)], + response_model=OrganizationSchema.GetSingleOrganizationSchema, + tags=["Organizations"], +) +async def create_organization( + organization_data: OrganizationSchema.NewOrganization, + current_user: User = Depends(get_current_active_user), +): + """Create a new organization.""" + return organization.create_organization(organization_data, current_user) -@api_router.get( - "/v2/users", - response_model=List[UserResponseV2], +@api_router.post( + "/organizations_upsert", dependencies=[Depends(get_current_active_user)], - tags=["Users"], + response_model=OrganizationSchema.GetSingleOrganizationSchema, + tags=["Organizations"], ) -async def call_get_users_v2( - state: Optional[str] = Query(None), - regionId: Optional[str] = Query(None), - invitePending: Optional[bool] = Query(None), +async def upsert_organization( + organization_data: OrganizationSchema.NewOrganization, current_user: User = Depends(get_current_active_user), ): - """Get users with filter.""" - return get_users_v2(state, regionId, invitePending, current_user) + """Upsert an organization.""" + return organization.upsert_organization(organization_data, current_user) @api_router.put( - "/v2/users/{user_id}", + "/organizations/{organization_id}", dependencies=[Depends(get_current_active_user)], - response_model=UserResponseV2, - tags=["Users"], + response_model=OrganizationSchema.GetSingleOrganizationSchema, + tags=["Organizations"], ) -async def update_user_v2_view( - user_id: str, - user_data: UpdateUserV2, +async def update_organization( + organization_id: str, + org_data: OrganizationSchema.NewOrganization, current_user: User = Depends(get_current_active_user), ): - """Update a particular user.""" - return update_user_v2(user_id, user_data, current_user) + """Update an organization by its ID.""" + return organization.update_organization(organization_id, org_data, current_user) -@api_router.post("/users/{userId}", tags=["Users"]) -async def call_update_user( - userId, body, current_user: User = Depends(get_current_active_user) +@api_router.delete( + "/organizations/{organization_id}", + dependencies=[Depends(get_current_active_user)], + response_model=OrganizationSchema.GenericMessageResponseModel, + tags=["Organizations"], +) +async def delete_organization( + organization_id: str, current_user: User = Depends(get_current_active_user) ): - """ - Update a user by ID. - Args: - userId : The ID of the user to update. - request : The HTTP request containing authorization and target for update. - - Raises: - HTTPException: If the user is not authorized or the user is not found. - - Returns: - JSONResponse: The result of the update. - """ - return update_user(userId, body, current_user) + """Delete an organization by its ID.""" + return organization.delete_organization(organization_id, current_user) -@api_router.put( - "/users/{user_id}/register/approve", +@api_router.post( + "/v2/organizations/{organization_id}/users", dependencies=[Depends(get_current_active_user)], - response_model=RegisterUserResponse, - tags=["Users"], + tags=["Organizations"], ) -async def register_approve( - user_id: str, current_user: User = Depends(get_current_active_user) +async def add_user_to_organization_v2( + organization_id: str, + user_data: OrganizationSchema.NewOrgUser, + current_user: User = Depends(get_current_active_user), ): - """Approve a registered user.""" - return user.approve_user_registration(user_id, current_user) + """Add a user to an organization.""" + return organization.add_user_to_org_v2(organization_id, user_data, current_user) -@api_router.put( - "/users/{user_id}/register/deny", +@api_router.post( + "/organizations/{organization_id}/roles/{role_id}/approve", dependencies=[Depends(get_current_active_user)], - response_model=RegisterUserResponse, - tags=["Users"], + response_model=OrganizationSchema.GenericMessageResponseModel, + tags=["Organizations"], ) -async def register_deny( - user_id: str, current_user: User = Depends(get_current_active_user) +async def approve_role( + organization_id: str, + role_id: str, + current_user: User = Depends(get_current_active_user), ): - """Deny a registered user.""" - return user.deny_user_registration(user_id, current_user) + """Approve a role within an organization.""" + return organization.approve_role(organization_id, role_id, current_user) @api_router.post( - "/users", + "/organizations/{organization_id}/roles/{role_id}/remove", dependencies=[Depends(get_current_active_user)], - response_model=NewUserResponseModel, - tags=["Users"], + response_model=OrganizationSchema.GenericMessageResponseModel, + tags=["Organizations"], ) -async def invite_user( - new_user: NewUser, current_user: User = Depends(get_current_active_user) +async def remove_role( + organization_id: str, + role_id: str, + current_user: User = Depends(get_current_active_user), ): - """Invite a user.""" - return user.invite(new_user, current_user) + """Remove a role from an organization.""" + return organization.remove_role(organization_id, role_id, current_user) -# ======================================== -# Api-Key Endpoints -# ======================================== +@api_router.post( + "/organizations/{organization_id}/granularScans/{scan_id}/update", + dependencies=[Depends(get_current_active_user)], + response_model=OrganizationSchema.GetSingleOrganizationSchema, + tags=["Organizations"], +) +async def update_granular_scan( + organization_id: str, + scan_id: str, + scan_data: OrganizationSchema.NewOrgScan, + current_user: User = Depends(get_current_active_user), +): + """Update a granular scan for an organization.""" + return organization.update_org_scan( + organization_id, scan_id, scan_data, current_user + ) -# POST -@api_router.post("/api-keys", response_model=ApiKeySchema, tags=["API Keys"]) -async def create_api_key(current_user: User = Depends(get_current_active_user)): - """Create api key.""" - return api_key_methods.post(current_user) +@api_router.get( + "/v2/organizations", + dependencies=[Depends(get_current_active_user)], + response_model=List[OrganizationSchema.GetOrganizationSchema], + tags=["Organizations"], +) +async def list_organizations_v2( + state: Optional[List[str]] = Query(None), + regionId: Optional[List[str]] = Query(None), + current_user: User = Depends(get_current_active_user), +): + """Retrieve a list of all organizations (version 2).""" + return organization.list_organizations_v2(state, regionId, current_user) -# DELETE -@api_router.delete("/api-keys/{id}", tags=["API Keys"]) -async def delete_api_key( - id: str, current_user: User = Depends(get_current_active_user) +@api_router.post( + "/search/organizations", + dependencies=[Depends(get_current_active_user)], + tags=["Organizations"], +) +async def search_organizations( + search_body: OrganizationSchema.OrganizationSearchBody, + current_user: User = Depends(get_current_active_user), ): - """Delete api key by id.""" - return api_key_methods.delete(id, current_user) + """Search for organizations in Elasticsearch.""" + return organization.search_organizations_task(search_body, current_user) # ======================================== -# Saved Search Endpoints +# Saved Searches # ======================================== @@ -683,105 +729,43 @@ async def get_api_key(id: str, current_user: User = Depends(get_current_active_u # ======================================== -# Notification Endpoints +# Scans # ======================================== -# POST -@api_router.post( - "/notifications", response_model=NotificationSchema, tags=["Notifications"] +@api_router.get( + "/scans", + dependencies=[Depends(get_current_active_user)], + response_model=scanSchema.GetScansResponseModel, + tags=["Scans"], ) -async def create_notification(current_user: User = Depends(get_current_active_user)): - """Create notification key.""" - # return notification_handler.post(current_user) - return [] +async def list_scans(current_user: User = Depends(get_current_active_user)): + """Retrieve a list of all scans.""" + return scan.list_scans(current_user) -# DELETE -@api_router.delete( - "/notifications/{id}", response_model=NotificationSchema, tags=["Notifications"] +@api_router.get( + "/granularScans", + dependencies=[Depends(get_current_active_user)], + response_model=scanSchema.GetGranularScansResponseModel, + tags=["Scans"], ) -async def delete_notification( - id: str, current_user: User = Depends(get_current_active_user) +async def list_granular_scans(current_user: User = Depends(get_current_active_user)): + """Retrieve a list of granular scans. User must be authenticated.""" + return scan.list_granular_scans(current_user) + + +@api_router.post( + "/scans", + dependencies=[Depends(get_current_active_user)], + response_model=scanSchema.CreateScanResponseModel, + tags=["Scans"], +) +async def create_scan( + scan_data: scanSchema.NewScan, current_user: User = Depends(get_current_active_user) ): - """Delete notification by id.""" - return notification_methods.delete(id, current_user) - - -# GET ALL: Doesn't require authentication -@api_router.get( - "/notifications", response_model=List[NotificationSchema], tags=["Notifications"] -) -async def get_all_notifications(): - """Get all notifications.""" - return notification_methods.get_all() - - -# GET BY ID -@api_router.get( - "/notifications/{id}", response_model=NotificationSchema, tags=["Notifications"] -) -async def get_notification( - id: str, current_user: User = Depends(get_current_active_user) -): - """Get notification by id.""" - return notification_methods.get_by_id(id, current_user) - - -# UPDATE BY ID -@api_router.put("/notifications/{id}", tags=["Notifications"]) -async def update_notification( - id: str, current_user: User = Depends(get_current_active_user) -): - """Update notification key by id.""" - return notification_methods.delete(id, current_user) - - -# GET 508 Banner: Doesn't require authentication -@api_router.get("/notifications/508-banner", tags=["Notifications"]) -async def get_508_banner(): - """Get notification by id.""" - return notification_methods.get_508_banner() - - -# ======================================== -# Scan Endpoints -# ======================================== - - -@api_router.get( - "/scans", - dependencies=[Depends(get_current_active_user)], - response_model=scanSchema.GetScansResponseModel, - tags=["Scans"], -) -async def list_scans(current_user: User = Depends(get_current_active_user)): - """Retrieve a list of all scans.""" - return scan.list_scans(current_user) - - -@api_router.get( - "/granularScans", - dependencies=[Depends(get_current_active_user)], - response_model=scanSchema.GetGranularScansResponseModel, - tags=["Scans"], -) -async def list_granular_scans(current_user: User = Depends(get_current_active_user)): - """Retrieve a list of granular scans. User must be authenticated.""" - return scan.list_granular_scans(current_user) - - -@api_router.post( - "/scans", - dependencies=[Depends(get_current_active_user)], - response_model=scanSchema.CreateScanResponseModel, - tags=["Scans"], -) -async def create_scan( - scan_data: scanSchema.NewScan, current_user: User = Depends(get_current_active_user) -): - """Create a new scan.""" - return scan.create_scan(scan_data, current_user) + """Create a new scan.""" + return scan.create_scan(scan_data, current_user) @api_router.get( @@ -844,7 +828,84 @@ async def invoke_scheduler(current_user: User = Depends(get_current_active_user) # ======================================== -# Stats Endpoints +# Scan Tasks +# ======================================== + + +@api_router.post( + "/scan-tasks/search", + dependencies=[Depends(get_current_active_user)], + response_model=scanTaskSchema.ScanTaskListResponse, + tags=["Scan Tasks"], +) +async def list_scan_tasks( + search_data: Optional[scanTaskSchema.ScanTaskSearch] = Body(None), + current_user: User = Depends(get_current_active_user), +): + """List scan tasks based on filters.""" + return scan_tasks.list_scan_tasks(search_data, current_user) + + +@api_router.post( + "/scan-tasks/{scan_task_id}/kill", + dependencies=[Depends(get_current_active_user)], + tags=["Scan Tasks"], +) +async def kill_scan_tasks( + scan_task_id: UUID, current_user: User = Depends(get_current_active_user) +): + """Kill a scan task.""" + return scan_tasks.kill_scan_task(scan_task_id, current_user) + + +@api_router.get( + "/scan-tasks/{scan_task_id}/logs", + dependencies=[Depends(get_current_active_user)], + # response_model=scanTaskSchema.GenericResponse, + tags=["Scan Tasks"], +) +async def get_scan_task_logs( + scan_task_id: UUID, current_user: User = Depends(get_current_active_user) +): + """Get logs from a particular scan task.""" + return scan_tasks.get_scan_task_logs(scan_task_id, current_user) + + +# ======================================== +# Search +# ======================================== + + +@api_router.post( + "/search", + dependencies=[Depends(get_current_active_user)], + response_model=SearchResponse, + tags=["Search"], +) +async def search(request: SearchRequest): + try: + search_post(request) + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e) + ) + + +@api_router.post( + "/search/export", dependencies=[Depends(get_current_active_user)], tags=["Search"] +) +async def export_endpoint(request: Request): + try: + body = await request.json() + search_body = SearchBody(**body) # Parse request body into SearchBody + result = export(search_body, request) + return result + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + + +# ======================================== +# Stats # ======================================== @@ -964,300 +1025,264 @@ async def get_by_org( # ======================================== -# Scan Task Endpoints +# Testing # ======================================== -@api_router.post( - "/scan-tasks/search", - dependencies=[Depends(get_current_active_user)], - response_model=scanTaskSchema.ScanTaskListResponse, - tags=["Scan Tasks"], -) -async def list_scan_tasks( - search_data: Optional[scanTaskSchema.ScanTaskSearch] = Body(None), - current_user: User = Depends(get_current_active_user), -): - """List scan tasks based on filters.""" - return scan_tasks.list_scan_tasks(search_data, current_user) +# Healthcheck endpoint +@api_router.get("/healthcheck", tags=["Testing"]) +async def healthcheck(): + """ + Healthcheck endpoint. + Returns: + dict: A dictionary containing the health status of the application. + """ + return {"status": "ok"} -@api_router.post( - "/scan-tasks/{scan_task_id}/kill", - dependencies=[Depends(get_current_active_user)], - tags=["Scan Tasks"], -) -async def kill_scan_tasks( - scan_task_id: UUID, current_user: User = Depends(get_current_active_user) -): - """Kill a scan task.""" - return scan_tasks.kill_scan_task(scan_task_id, current_user) +# ======================================== +# Users +# ======================================== -@api_router.get( - "/scan-tasks/{scan_task_id}/logs", + +@api_router.post( + "/users/me/acceptTerms", + response_model=UserSchema, dependencies=[Depends(get_current_active_user)], - # response_model=scanTaskSchema.GenericResponse, - tags=["Scan Tasks"], + tags=["Users"], ) -async def get_scan_task_logs( - scan_task_id: UUID, current_user: User = Depends(get_current_active_user) +async def call_accept_terms( + version_data: VersionModel, current_user: User = Depends(get_current_active_user) ): - """Get logs from a particular scan task.""" - return scan_tasks.get_scan_task_logs(scan_task_id, current_user) + """Accept the latest terms of service.""" + return accept_terms(version_data, current_user) -# ======================================== -# Organization Endpoints -# ======================================== + +@api_router.get("/users/me", tags=["Users"]) +async def read_users_me(current_user: User = Depends(get_current_active_user)): + return get_me(current_user) -@api_router.get( - "/organizations", +@api_router.delete( + "/users/{userId}", + response_model=OrganizationSchema.GenericMessageResponseModel, dependencies=[Depends(get_current_active_user)], - response_model=List[OrganizationSchema.GetOrganizationSchema], - tags=["Organizations"], + tags=["Users"], ) -async def list_organizations(current_user: User = Depends(get_current_active_user)): - """Retrieve a list of all organizations.""" - return organization.list_organizations(current_user) +async def call_delete_user( + userId: str, current_user: User = Depends(get_current_active_user) +): + """Delete user.""" + return delete_user(userId, current_user) @api_router.get( - "/organizations/tags", + "/users", + response_model=List[UserResponseV2], dependencies=[Depends(get_current_active_user)], - response_model=List[OrganizationSchema.GetTagSchema], - tags=["Organizations"], + tags=["Users"], ) -async def get_organization_tags(current_user: User = Depends(get_current_active_user)): - """Retrieve a list of organization tags.""" - return organization.get_tags(current_user) +async def call_get_users(current_user: User = Depends(get_current_active_user)): + """Get all users.""" + return get_users(current_user) @api_router.get( - "/organizations/{organization_id}", + "/users/regionId/{regionId}", + response_model=List[UserSchema], dependencies=[Depends(get_current_active_user)], - response_model=OrganizationSchema.GetSingleOrganizationSchema, - tags=["Organizations"], + tags=["Users"], ) -async def get_organization( - organization_id: str, current_user: User = Depends(get_current_active_user) +async def call_get_users_by_region_id( + regionId, current_user: User = Depends(get_current_active_user) ): - """Retrieve an organization by its ID.""" - return organization.get_organization(organization_id, current_user) + """ + Call get_users_by_region_id() + Args: + request : The HTTP request containing query parameters. + Raises: + HTTPException: If the user is not authorized or no users are found. -@api_router.get( - "/organizations/state/{state}", - dependencies=[Depends(get_current_active_user)], - response_model=List[OrganizationSchema.GetOrganizationSchema], - tags=["Organizations"], -) -async def get_organizations_by_state( - state: str, current_user: User = Depends(get_current_active_user) -): - """Retrieve organizations by state.""" - return organization.get_by_state(state, current_user) + Returns: + List[User]: A list of users matching the filter criteria. + """ + return get_users_by_region_id(regionId, current_user) @api_router.get( - "/organizations/regionId/{region_id}", + "/users/state/{state}", + response_model=List[UserSchema], dependencies=[Depends(get_current_active_user)], - response_model=List[OrganizationSchema.GetOrganizationSchema], - tags=["Organizations"], + tags=["Users"], ) -async def get_organizations_by_region( - region_id: str, current_user: User = Depends(get_current_active_user) +async def call_get_users_by_state( + state, current_user: User = Depends(get_current_active_user) ): - """Retrieve organizations by region ID.""" - return organization.get_by_region(region_id, current_user) - - -@api_router.get( - "/regions", - dependencies=[Depends(get_current_active_user)], - response_model=List[OrganizationSchema.RegionSchema], - tags=["Regions"], -) -async def list_regions(current_user: User = Depends(get_current_active_user)): - """Retrieve a list of all regions.""" - return organization.get_all_regions(current_user) + """ + Call get_users_by_state() + Args: + request : The HTTP request containing query parameters. + Raises: + HTTPException: If the user is not authorized or no users are found. -@api_router.post( - "/organizations", - dependencies=[Depends(get_current_active_user)], - response_model=OrganizationSchema.GetSingleOrganizationSchema, - tags=["Organizations"], -) -async def create_organization( - organization_data: OrganizationSchema.NewOrganization, - current_user: User = Depends(get_current_active_user), -): - """Create a new organization.""" - return organization.create_organization(organization_data, current_user) + Returns: + List[User]: A list of users matching the filter criteria. + """ + return get_users_by_state(state, current_user) -@api_router.post( - "/organizations_upsert", +@api_router.get( + "/v2/users", + response_model=List[UserResponseV2], dependencies=[Depends(get_current_active_user)], - response_model=OrganizationSchema.GetSingleOrganizationSchema, - tags=["Organizations"], + tags=["Users"], ) -async def upsert_organization( - organization_data: OrganizationSchema.NewOrganization, +async def call_get_users_v2( + state: Optional[str] = Query(None), + regionId: Optional[str] = Query(None), + invitePending: Optional[bool] = Query(None), current_user: User = Depends(get_current_active_user), ): - """Upsert an organization.""" - return organization.upsert_organization(organization_data, current_user) + """Get users with filter.""" + return get_users_v2(state, regionId, invitePending, current_user) @api_router.put( - "/organizations/{organization_id}", + "/v2/users/{user_id}", dependencies=[Depends(get_current_active_user)], - response_model=OrganizationSchema.GetSingleOrganizationSchema, - tags=["Organizations"], + response_model=UserResponseV2, + tags=["Users"], ) -async def update_organization( - organization_id: str, - org_data: OrganizationSchema.NewOrganization, +async def update_user_v2_view( + user_id: str, + user_data: UpdateUserV2, current_user: User = Depends(get_current_active_user), ): - """Update an organization by its ID.""" - return organization.update_organization(organization_id, org_data, current_user) + """Update a particular user.""" + return update_user_v2(user_id, user_data, current_user) -@api_router.delete( - "/organizations/{organization_id}", - dependencies=[Depends(get_current_active_user)], - response_model=OrganizationSchema.GenericMessageResponseModel, - tags=["Organizations"], -) -async def delete_organization( - organization_id: str, current_user: User = Depends(get_current_active_user) +@api_router.post("/users/{userId}", tags=["Users"]) +async def call_update_user( + userId, body, current_user: User = Depends(get_current_active_user) ): - """Delete an organization by its ID.""" - return organization.delete_organization(organization_id, current_user) + """ + Update a user by ID. + Args: + userId : The ID of the user to update. + request : The HTTP request containing authorization and target for update. + Raises: + HTTPException: If the user is not authorized or the user is not found. -@api_router.post( - "/v2/organizations/{organization_id}/users", - dependencies=[Depends(get_current_active_user)], - tags=["Organizations"], -) -async def add_user_to_organization_v2( - organization_id: str, - user_data: OrganizationSchema.NewOrgUser, - current_user: User = Depends(get_current_active_user), -): - """Add a user to an organization.""" - return organization.add_user_to_org_v2(organization_id, user_data, current_user) + Returns: + JSONResponse: The result of the update. + """ + return update_user(userId, body, current_user) -@api_router.post( - "/organizations/{organization_id}/roles/{role_id}/approve", +@api_router.put( + "/users/{user_id}/register/approve", dependencies=[Depends(get_current_active_user)], - response_model=OrganizationSchema.GenericMessageResponseModel, - tags=["Organizations"], + response_model=RegisterUserResponse, + tags=["Users"], ) -async def approve_role( - organization_id: str, - role_id: str, - current_user: User = Depends(get_current_active_user), +async def register_approve( + user_id: str, current_user: User = Depends(get_current_active_user) ): - """Approve a role within an organization.""" - return organization.approve_role(organization_id, role_id, current_user) + """Approve a registered user.""" + return user.approve_user_registration(user_id, current_user) -@api_router.post( - "/organizations/{organization_id}/roles/{role_id}/remove", +@api_router.put( + "/users/{user_id}/register/deny", dependencies=[Depends(get_current_active_user)], - response_model=OrganizationSchema.GenericMessageResponseModel, - tags=["Organizations"], + response_model=RegisterUserResponse, + tags=["Users"], ) -async def remove_role( - organization_id: str, - role_id: str, - current_user: User = Depends(get_current_active_user), +async def register_deny( + user_id: str, current_user: User = Depends(get_current_active_user) ): - """Remove a role from an organization.""" - return organization.remove_role(organization_id, role_id, current_user) + """Deny a registered user.""" + return user.deny_user_registration(user_id, current_user) @api_router.post( - "/organizations/{organization_id}/granularScans/{scan_id}/update", + "/users", dependencies=[Depends(get_current_active_user)], - response_model=OrganizationSchema.GetSingleOrganizationSchema, - tags=["Organizations"], + response_model=NewUserResponseModel, + tags=["Users"], ) -async def update_granular_scan( - organization_id: str, - scan_id: str, - scan_data: OrganizationSchema.NewOrgScan, - current_user: User = Depends(get_current_active_user), +async def invite_user( + new_user: NewUser, current_user: User = Depends(get_current_active_user) ): - """Update a granular scan for an organization.""" - return organization.update_org_scan( - organization_id, scan_id, scan_data, current_user - ) + """Invite a user.""" + return user.invite(new_user, current_user) -@api_router.get( - "/v2/organizations", - dependencies=[Depends(get_current_active_user)], - response_model=List[OrganizationSchema.GetOrganizationSchema], - tags=["Organizations"], -) -async def list_organizations_v2( - state: Optional[List[str]] = Query(None), - regionId: Optional[List[str]] = Query(None), - current_user: User = Depends(get_current_active_user), -): - """Retrieve a list of all organizations (version 2).""" - return organization.list_organizations_v2(state, regionId, current_user) +# ======================================== +# Vulnerabilities +# ======================================== @api_router.post( - "/search/organizations", + "/vulnerabilities/search", dependencies=[Depends(get_current_active_user)], - tags=["Organizations"], + response_model=List[VulnerabilitySchema], + tags=["Vulnerabilities"], ) -async def search_organizations( - search_body: OrganizationSchema.OrganizationSearchBody, +async def call_search_vulnerabilities( + vulnerability_search: VulnerabilitySearch, current_user: User = Depends(get_current_active_user), ): - """Search for organizations in Elasticsearch.""" - return organization.search_organizations_task(search_body, current_user) + try: + return search_vulnerabilities(vulnerability_search, current_user) + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) -# ======================================== -# Search Endpoints -# ======================================== +@api_router.post("/vulnerabilities/export", tags=["Vulnerabilities"]) +async def export_vulnerabilities(): + try: + pass + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) -@api_router.post( - "/search", +@api_router.get( + "/vulnerabilities/{vulnerabilityId}", dependencies=[Depends(get_current_active_user)], - response_model=SearchResponse, - tags=["Search"], + response_model=VulnerabilitySchema, + tags=["Vulnerabilities"], ) -async def search(request: SearchRequest): - try: - search_post(request) - except Exception as e: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e) - ) +async def call_get_vulnerability_by_id(vuln_id): + """ + Get vulnerability by id. + Returns: + object: a single Vulnerability object. + """ + return get_vulnerability_by_id(vuln_id) -@api_router.post( - "/search/export", dependencies=[Depends(get_current_active_user)], tags=["Search"] +@api_router.put( + "/vulnerabilities/{vulnerabilityId}", + dependencies=[Depends(get_current_active_user)], + response_model=VulnerabilitySchema, + tags=["Vulnerabilities"], ) -async def export_endpoint(request: Request): - try: - body = await request.json() - search_body = SearchBody(**body) # Parse request body into SearchBody - result = export(search_body, request) - return result - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) +async def call_update_vulnerability( + vuln_id, + data: VulnerabilitySchema, + current_user: User = Depends(get_current_active_user), +): + """ + Update vulnerability by id. + + Returns: + object: a single vulnerability object that has been modified. + """ + return update_vulnerability(vuln_id, data, current_user)