diff --git a/apps/dashboard/src/main/java/com/akto/action/AdminSettingsAction.java b/apps/dashboard/src/main/java/com/akto/action/AdminSettingsAction.java index 5f5fb16b2d..5fc9352282 100644 --- a/apps/dashboard/src/main/java/com/akto/action/AdminSettingsAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/AdminSettingsAction.java @@ -23,6 +23,7 @@ import java.util.Set; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -349,6 +350,47 @@ public String updateUrlSettings() { } + private boolean updateFiltersFlag; + private String permissionValue; + + Map advancedFilterPermission; + + + + public String getAdvancedFilterFlagsForAccount(){ + AccountSettings accountSettings = AccountSettingsDao.instance.findOne(AccountSettingsDao.generateFilter()); + advancedFilterPermission = new HashMap<>(); + advancedFilterPermission.put(AccountSettings.ALLOW_FILTER_LOGS, accountSettings.getAllowFilterLogs()); + advancedFilterPermission.put(AccountSettings.ALLOW_DELETION_OF_REDUNDANT_URLS, accountSettings.getAllowDeletionOfUrls()); + + return SUCCESS.toUpperCase(); + } + + public String updatePermissionsForAdvancedFilters(){ + if(this.permissionValue.equals(AccountSettings.ALLOW_DELETION_OF_REDUNDANT_URLS) || this.permissionValue.equals(AccountSettings.ALLOW_FILTER_LOGS)){ + AccountSettingsDao.instance.updateOne( + AccountSettingsDao.generateFilter(), + Updates.set(this.permissionValue, this.updateFiltersFlag) + ); + return SUCCESS.toUpperCase(); + }else{ + addActionError("invalid permission"); + return ERROR.toUpperCase(); + } + } + + public void setUpdateFiltersFlag(boolean updateFiltersFlag) { + this.updateFiltersFlag = updateFiltersFlag; + } + + public void setPermissionValue(String permissionValue) { + this.permissionValue = permissionValue; + } + + public Map getAdvancedFilterPermission() { + return advancedFilterPermission; + } + public AccountSettings getAccountSettings() { return this.accountSettings; } diff --git a/apps/dashboard/src/main/java/com/akto/action/settings/AdvancedTrafficFiltersAction.java b/apps/dashboard/src/main/java/com/akto/action/settings/AdvancedTrafficFiltersAction.java index 769ee51d9b..48f2158e20 100644 --- a/apps/dashboard/src/main/java/com/akto/action/settings/AdvancedTrafficFiltersAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/settings/AdvancedTrafficFiltersAction.java @@ -1,21 +1,28 @@ package com.akto.action.settings; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.bson.conversions.Bson; import com.akto.action.UserAction; +import com.akto.dao.ApiCollectionsDao; +import com.akto.dao.context.Context; import com.akto.dao.monitoring.FilterConfigYamlParser; import com.akto.dao.runtime_filters.AdvancedTrafficFiltersDao; +import com.akto.dto.ApiCollection; import com.akto.dto.monitoring.FilterConfig; import com.akto.dto.test_editor.YamlTemplate; import com.akto.util.Constants; import com.akto.utils.TrafficFilterUtil; +import com.akto.utils.jobs.CleanInventory; import com.mongodb.client.model.Filters; import com.mongodb.client.model.FindOneAndUpdateOptions; import com.mongodb.client.model.Projections; import com.mongodb.client.model.Sorts; import com.mongodb.client.model.Updates; +import com.opensymphony.xwork2.Action; public class AdvancedTrafficFiltersAction extends UserAction { @@ -82,6 +89,30 @@ public String deleteAdvancedFilter(){ return SUCCESS.toUpperCase(); } + public String syncTrafficFromFilters(){ + FilterConfig filterConfig = new FilterConfig(); + try { + filterConfig = FilterConfigYamlParser.parseTemplate(yamlContent, true); + if (filterConfig.getId() == null) { + throw new Exception("id field cannot be empty"); + } + if (filterConfig.getFilter() == null) { + throw new Exception("filter field cannot be empty"); + } + + List apiCollections = ApiCollectionsDao.instance.findAll( + Filters.empty(), Projections.include(ApiCollection.HOST_NAME)); + YamlTemplate yamlTemplate = new YamlTemplate(filterConfig.getId(), Context.now(), getSUser().getLogin(), Context.now(), this.yamlContent, null); + + CleanInventory.cleanFilteredSampleDataFromAdvancedFilters(apiCollections,Arrays.asList(yamlTemplate),new ArrayList<>() , "", false, true); + return Action.SUCCESS.toUpperCase(); + } catch (Exception e) { + e.printStackTrace(); + addActionError(e.getMessage()); + return ERROR.toUpperCase(); + } + } + public List getTemplatesList() { return templatesList; } diff --git a/apps/dashboard/src/main/java/com/akto/listener/InitializerListener.java b/apps/dashboard/src/main/java/com/akto/listener/InitializerListener.java index 90ea64dfaf..43a3023c8a 100644 --- a/apps/dashboard/src/main/java/com/akto/listener/InitializerListener.java +++ b/apps/dashboard/src/main/java/com/akto/listener/InitializerListener.java @@ -653,7 +653,7 @@ public void accept(Account account) { ); List redundantUrlList = accountSettings.getAllowRedundantEndpointsList(); try { - CleanInventory.cleanFilteredSampleDataFromAdvancedFilters(apiCollections , yamlTemplates, redundantUrlList,filePath, shouldDeleteApis); + CleanInventory.cleanFilteredSampleDataFromAdvancedFilters(apiCollections , yamlTemplates, redundantUrlList,filePath, shouldDeleteApis, false); } catch (Exception e) { e.printStackTrace(); } diff --git a/apps/dashboard/src/main/java/com/akto/utils/jobs/CleanInventory.java b/apps/dashboard/src/main/java/com/akto/utils/jobs/CleanInventory.java index ffbc502f44..74c0a6ac83 100644 --- a/apps/dashboard/src/main/java/com/akto/utils/jobs/CleanInventory.java +++ b/apps/dashboard/src/main/java/com/akto/utils/jobs/CleanInventory.java @@ -125,7 +125,7 @@ private static void cleanInventoryJob() { } - public static void cleanFilteredSampleDataFromAdvancedFilters(List apiCollections, List yamlTemplates, List redundantUrlList, String filePath, boolean shouldDeleteRequest) throws IOException{ + public static void cleanFilteredSampleDataFromAdvancedFilters(List apiCollections, List yamlTemplates, List redundantUrlList, String filePath, boolean shouldDeleteRequest, boolean saveLogsToDB) throws IOException{ Map apiCollectionMap = apiCollections.stream().collect(Collectors.toMap(ApiCollection::getId, Function.identity())); // BufferedWriter writer = new BufferedWriter(new FileWriter(new File(filePath))); @@ -185,15 +185,32 @@ public static void cleanFilteredSampleDataFromAdvancedFilters(List + + + + + ADMIN_ACTIONS + READ_WRITE + + + 403 + false + ^actionErrors.* + + + + + 422 + false + ^actionErrors.* + + + + + + + + ADMIN_ACTIONS + READ_WRITE + + + 403 + false + ^actionErrors.* + + + + + 422 + false + ^actionErrors.* + + + + + + + + USER_ACTIONS + READ + + + 403 + false + ^actionErrors.* + + + advancedFilterPermission + + + 422 + false + ^actionErrors.* + + + diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/health_logs/Logs.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/health_logs/Logs.jsx index 075f3ffac0..d843e6622f 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/health_logs/Logs.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/health_logs/Logs.jsx @@ -12,7 +12,7 @@ const Logs = () => { const [ logs, setLogs ] = useState({ startTime: null, endTime: null, - logGroup: '', + logGroup: 'DASHBOARD', logData: [] }) const [ loading, setLoading ] = useState(false) @@ -103,7 +103,7 @@ const Logs = () => {
diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/traffic-conditions/AdvancedTrafficFilters.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/traffic-conditions/AdvancedTrafficFilters.jsx index 529ddb98aa..36852b046e 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/traffic-conditions/AdvancedTrafficFilters.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/traffic-conditions/AdvancedTrafficFilters.jsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react' import PageWithMultipleCards from '../../../components/layouts/PageWithMultipleCards' -import { Box, Button, HorizontalStack, Icon, LegacyCard, Text, Tooltip, VerticalStack } from '@shopify/polaris' +import { Box, Button, Checkbox, HorizontalStack, Icon, LegacyCard, Modal, Popover, Text, Tooltip, VerticalStack } from '@shopify/polaris' import trafficFiltersRequest from './api' import func from "@/util/func" import TitleWithInfo from "@/apps/dashboard/components/shared/TitleWithInfo" @@ -15,6 +15,9 @@ function AdvancedTrafficFilters() { const [templateList, setTemplateList] = useState([]) const [currentId, setCurrentId] = useState("") const [currentState, setCurrentState] = useState(false) + const [modalActive, setModalActive] = useState(false); + const [popoverActive, setPopoverActive] = useState(false); + const [permissionsMap,setPermissionsMap] = useState({}) const fetchData = async () => { await trafficFiltersRequest.getAdvancedFiltersForTraffic().then((resp) => { @@ -29,6 +32,9 @@ function AdvancedTrafficFilters() { } }) + await trafficFiltersRequest.getAdvancedFiltersPermissions().then((resp) => { + setPermissionsMap(resp) + }) } useEffect(() => { @@ -47,6 +53,14 @@ function AdvancedTrafficFilters() { } + const handleDryRun = async(content) => { + if(window.IS_SAAS === "false"){ + await trafficFiltersRequest.dryRunAdvancedFilters(content).then((res)=> { + window.open("/dashboard/settings/logs", "_blank") + }) + } + } + const resetFunc = () => { setCurrentTemplate({message: ''}); setOgData({message: ''}); @@ -81,13 +95,50 @@ function AdvancedTrafficFilters() { setCurrentState(state) } + const handleCheckboxClicked = async(permission, value) => { + await trafficFiltersRequest.updateAdvancedFiltersPermissions(value, permission).then((res) => { + setPermissionsMap((prev) => { + prev[permission] = value + return {...prev} + }) + }) + } + const tooltipText= currentState ? "Mark as Active" : "Mark as Deactive" + const titleComp = ( + + Add or modify filters + setPopoverActive(!popoverActive)}>Actions} + active={popoverActive} + onClose={() => setPopoverActive(false)} + autofocusTarget="container" + > + + + handleCheckboxClicked('allowFilterLogs', !permissionsMap['allowFilterLogs'])} + /> + handleCheckboxClicked('allowDeletionOfUrls', !permissionsMap['allowDeletionOfUrls'])} + /> + + + + + ) + return( + <> Add or modify filters)} + title={titleComp} footerActionAlignment="right" - primaryFooterAction={{content: 'Save', onAction: () => handleSave(currentTemplate), + primaryFooterAction={{content: 'Save', onAction: () => setModalActive(true), disabled: (currentTemplate?.message !== undefined && currentTemplate.message.length === 0) || (typeof (currentTemplate) === 'string' && currentTemplate.length === 0) }} secondaryFooterActions={[{content: 'Add new', onAction: () => resetFunc()}]} @@ -129,6 +180,21 @@ function AdvancedTrafficFilters() { + setModalActive(false)} + primaryAction={{content: 'Save', onAction: () => handleSave(currentTemplate)}} + secondaryActions={window.IS_SAAS !== "true" ? [{content: 'Dry run', onAction: () => handleDryRun(currentTemplate)}]: []} + title={"Add advanced filters"} + > + + + Adding an filter will stop/modify traffic ingestion in the dashboard. + Are you sure you want to add the filter? + + + + ) } diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/traffic-conditions/api.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/traffic-conditions/api.js index 67ac60809e..71c1e1cbd2 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/traffic-conditions/api.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/traffic-conditions/api.js @@ -10,24 +10,45 @@ const trafficFiltersRequest = { }, updateAdvancedFiltersForTraffic(yamlContent) { return request({ - url: 'api/addAdvancedFiltersForTraffic', + url: '/api/addAdvancedFiltersForTraffic', method: 'post', data: {yamlContent} }) }, deleteFilter(id) { return request({ - url: 'api/deleteAdvancedFilter', + url: '/api/deleteAdvancedFilter', method: 'post', data: {templateId: id} }) }, changeStateOfFilter(id, inactive) { return request({ - url: 'api/changeStateOfFilter', + url: '/api/changeStateOfFilter', method: 'post', data: {templateId: id, inactive: inactive} }) + }, + dryRunAdvancedFilters(yamlContent){ + return request({ + url: '/api/dryRunAdvancedFilters', + method: 'post', + data: {yamlContent} + }) + }, + getAdvancedFiltersPermissions(){ + return request({ + url: '/api/getAccountSettingsForAdvancedFilters', + method: 'post', + data: {} + }) + }, + updateAdvancedFiltersPermissions(updateFiltersFlag, permissionValue){ + return request({ + url: '/api/updateRetrospectiveFilterSettings', + method: 'post', + data: {updateFiltersFlag, permissionValue} + }) } }