diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e4f7434c5f..6bfd068f08 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,7 +36,7 @@ If you find a bug or have an idea for a new feature, please open an issue on Git ## License -By contributing to this project, you agree that your contributions will be licensed under the [LICENSE](LICENSE) file. +By contributing to this project, you agree that your contributions will be licensed under the [LICENSE](https://github.com/akto-api-security/akto/blob/master/LICENSE.md) file. ## Contact diff --git a/apps/dashboard/src/main/java/com/akto/listener/RuntimeListener.java b/apps/dashboard/src/main/java/com/akto/listener/RuntimeListener.java index f73d8104ba..3e6bc319b7 100644 --- a/apps/dashboard/src/main/java/com/akto/listener/RuntimeListener.java +++ b/apps/dashboard/src/main/java/com/akto/listener/RuntimeListener.java @@ -238,7 +238,7 @@ public static void addLlmSampleData(int accountId) { } try { - String mockServiceUrl = "http://sampl-aktol-1exannwybqov-67928726.ap-south-1.elb.amazonaws.com:5000"; + String mockServiceUrl = "https://vuln-llm.akto.io"; String data = convertStreamToString(InitializerListener.class.getResourceAsStream("/LlmSampleApiData.json")); JSONArray dataobject = new JSONArray(data); for (Object obj: dataobject) { diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/DropdownSearch.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/DropdownSearch.jsx index 373ba57eac..5b18124b63 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/DropdownSearch.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/DropdownSearch.jsx @@ -6,7 +6,7 @@ function DropdownSearch(props) { const id = props.id ? props.id : "dropdown-search" - const { disabled, label, placeholder, optionsList, setSelected, value , avatarIcon, preSelected, allowMultiple, itemName} = props + const { disabled, label, placeholder, optionsList, setSelected, value , avatarIcon, preSelected, allowMultiple, itemName, dropdownSearchKey} = props const deselectedOptions = optionsList const [selectedOptions, setSelectedOptions] = useState(preSelected ? preSelected : []); @@ -56,8 +56,9 @@ function DropdownSearch(props) { return; } const filterRegex = new RegExp(value, 'i'); + const searchKey = dropdownSearchKey ? dropdownSearchKey : "label" const resultOptions = deselectedOptions.filter((option) => - option.label.match(filterRegex), + option[searchKey].match(filterRegex) ); setOptions(resultOptions); setLoading(false); diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/customDiffEditor.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/customDiffEditor.js index 7ade628db8..037c4295ac 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/customDiffEditor.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/customDiffEditor.js @@ -77,7 +77,7 @@ const transform = { if(!isNaN(key)){ ret.push(parsedJson[key]) }else{ - ret.push({key: parsedJson[key]}) + ret.push({[key]: parsedJson[key]}) } }) return JSON.stringify(ret, null, 2) diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiCollections.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiCollections.jsx index 41626613a5..0648d2ffc7 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiCollections.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiCollections.jsx @@ -153,7 +153,7 @@ function ApiCollections() { }} > - +
func.handleKeyPress(e, createNewCollection)}> - +
) diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/QuickStart.css b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/QuickStart.css index ec9cf4f379..2b4c218085 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/QuickStart.css +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/QuickStart.css @@ -69,4 +69,14 @@ .update-connections .Polaris-Page--divider{ padding-top: 20px !important; +} + +.overflow-text{ + text-overflow: ellipsis; + overflow-x: hidden; + white-space: nowrap; +} + +.right-card .Polaris-Scrollable{ + overflow-x: hidden; } \ No newline at end of file diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/api.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/api.js index a29a6e8b91..fe81939abd 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/api.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/api.js @@ -67,6 +67,24 @@ const api = { method: 'post', data: {deploymentMethod} }) + }, + fetchBurpPluginDownloadLink() { + return request({ + url: '/api/fetchBurpPluginDownloadLink', + method: 'post', + data: {}, + }).then((resp) => { + return resp + }) + }, + fetchBurpCredentials() { + return request({ + url: '/api/fetchBurpCredentials', + method: 'post', + data: {}, + }).then((resp) => { + return resp + }) } } diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/components/BurpSource.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/components/BurpSource.jsx index 76ccb3d3ac..4edb61020b 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/components/BurpSource.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/components/BurpSource.jsx @@ -1,77 +1,104 @@ -import { Button, ButtonGroup, HorizontalStack, Icon, Spinner, Text, VerticalStack } from '@shopify/polaris' -import React, { useState } from 'react' -import { StatusActiveMajor } from "@shopify/polaris-icons" +import { Box, Button, ButtonGroup, HorizontalStack, Text, VerticalStack } from '@shopify/polaris' +import React, { useEffect, useState } from 'react' import {useNavigate} from "react-router-dom" import api from '../api' -import func from '@/util/func' - +import func from "@/util/func" + function BurpSource() { + const navigate = useNavigate() + const [burpGithubLink, setBurpGithubLink] = useState(""); + const [aktoIp, setAktoIp] = useState(""); + const [aktoToken, setAktoToken] = useState(""); + const [burpCollectionURL, setBurpCollectionURL] = useState("") + + const getGithubLink = async() => { + await api.fetchBurpPluginDownloadLink().then((resp) => { + if (resp && resp.burpGithubLink) { + setBurpGithubLink(resp?.burpGithubLink) + } + }) + } + + const getCredentials = async() => { + await api.fetchBurpCredentials().then((resp) => { + if (!resp) return + setAktoIp(resp?.host) + setAktoToken(resp?.apiToken?.key) + }) + } + + const downloadBurpJar = async() => { + let downloadTime = func.timeNow() + let showBurpPluginConnectedFlag = false - const [downloadInfo, setDownloadInfo] = useState(0) - const [initialData, setInitialData] = useState(0) - const [finalData, setFinalData] = useState(0) - - const downloadBurpExt = async() => { - setDownloadInfo(1) - await api.downloadBurpPluginJar().then((resp)=> { - let downloadTime = func.timeNow() - - const href = URL.createObjectURL(resp); - // create "a" HTML element with href to file & click - const link = document.createElement('a'); - link.href = href; - link.setAttribute('download', 'Akto.jar'); //or any other extension - document.body.appendChild(link); - link.click(); - // clean up "a" element & remove ObjectURL - document.body.removeChild(link); - URL.revokeObjectURL(href); - - setDownloadInfo(2) - setInitialData(1) - - let interval = setInterval(() => { - api.fetchBurpPluginInfo().then((response) => { - let lastBootupTimestamp = response.burpPluginInfo.lastBootupTimestamp + await api.downloadBurpPluginJar() + window.open(burpGithubLink) + + let interval = setInterval(() => { + api.fetchBurpPluginInfo().then((response) => { + let lastBootupTimestamp = response?.burpPluginInfo?.lastBootupTimestamp if (lastBootupTimestamp > downloadTime) { - setInitialData(2) - setFinalData(1) + if (showBurpPluginConnectedFlag) { + func.setToast(true, false, "Burp plugin connected") + } + showBurpPluginConnectedFlag = false if (response.burpPluginInfo.lastDataSentTimestamp > downloadTime) { clearInterval(interval) - setFinalData(2) + setBurpCollectionURL("/dashboard/observe/inventory") + func.setToast(true, false, "Data received from burp plugin") } } }) - }, 5000) - }) + }, 2000) + } - const navigate = useNavigate() - const DownloadTextComponent = ({param_value}) => { - switch(param_value){ - case 1: - return () - case 2: - return (
) - default: - return null - } + const copyText = (text,messageText) => { + navigator.clipboard.writeText(text) + func.setToast(true, false, `${messageText} is copied to clipboard.`) } const steps = [ { - text: "Download Akto's Burp extension.", - component:
, - textComponent: + text: "Download akto's burp extension", + component: , + }, + { + text: "Open Burp and add the downloaded jar file in extension tab." + }, + { + text: 'Once the plugin is loaded click on "options" tab inside the plugin.' }, { - text: "Open Burp and add the downloaded jar file in extension tab.", - textComponent: + text: "Copy the AKTO_IP and AKTO_TOKEN and paste in the options tab.", + component: ( + + + + AKTO_IP: + + + + AKTO_TOKEN: + + + + + ) }, { - text: "Start Burp proxy and browse any website. You will see traffic in 'Burp' collection in inventory.", - textComponent: , - component: finalData === 2 ? : null + text: "Start Burp proxy and browse any website.", + component: ( + + You will see traffic in + {burpCollectionURL.length > 0 ? : Burp} + collection. + + ) } ] @@ -83,6 +110,11 @@ function BurpSource() { navigate("/dashboard/settings/integrations/burp") } + useEffect(()=> { + getGithubLink() + getCredentials() + },[]) + return (
@@ -93,14 +125,10 @@ function BurpSource() { {steps.map((element,index) => ( - {index + 1}. - {element.text} - {element.textComponent} - - -
- {element.component} + {index + 1}. + {element?.text} + {element?.component} ))} diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/components/NewConnection.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/components/NewConnection.jsx index 8cb8d5ca16..4291d4577f 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/components/NewConnection.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/quick_start/components/NewConnection.jsx @@ -106,7 +106,7 @@ function NewConnection() { const trafficScreenLabel = (
- setConnector(item)}/> + setConnector(item)} dropdownSearchKey="value"/> {connectors?.component}
diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/TestEditor.css b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/TestEditor.css index 2acef9d4e2..fadaf9e55b 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/TestEditor.css +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/TestEditor.css @@ -58,4 +58,12 @@ .editor-header .Polaris-Text--root{ max-width: 30vw; +} + +.req-resp-tabs .Polaris-LegacyTabs__Title{ + padding: 8px 0 !important; +} + +.req-resp-tabs .Polaris-Box{ + border: none !important; } \ No newline at end of file diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/components/SampleApi.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/components/SampleApi.jsx index a14dbf993f..86c1c67e82 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/components/SampleApi.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/components/SampleApi.jsx @@ -1,6 +1,5 @@ -import { Box, Button, Divider, Frame, HorizontalStack, LegacyTabs, Modal, VerticalStack} from "@shopify/polaris" -import { tokens } from "@shopify/polaris-tokens" -import { UpdateInventoryMajor, ChevronUpMinor } from "@shopify/polaris-icons" +import { Box, Button, Divider, Frame, HorizontalStack, LegacyTabs, Modal, Text, Tooltip} from "@shopify/polaris" +import {ChevronUpMinor } from "@shopify/polaris-icons" import { useEffect, useRef, useState } from "react"; @@ -122,12 +121,12 @@ const SampleApi = () => { const handleTabChange = (selectedTabIndex) => { setSelected(selectedTabIndex) - if (sampleData) { + if (selectedTabIndex == 0) { - editorInstance.setValue(JSON.stringify(sampleData.requestJson["json"], null, 2)) + editorInstance.setValue('\n' + sampleData?.requestJson["firstLine"] + '\n\n' + JSON.stringify(sampleData.requestJson["json"], null, 2)) } else { - editorInstance.setValue(JSON.stringify(sampleData.responseJson["json"], null, 2)) + editorInstance.setValue('\n' + sampleData?.responseJson["firstLine"] + '\n\n' + JSON.stringify(sampleData.responseJson["json"], null, 2)) } } } @@ -167,7 +166,7 @@ const SampleApi = () => { setSampleData({ requestJson, responseJson }) if (editorInstance) { - editorInstance.setValue(JSON.stringify(requestJson["json"], null, 2)) + editorInstance.setValue('\n' + requestJson["firstLine"] + '\n\n' + JSON.stringify(requestJson["json"], null, 2)) } setTimeout(()=> { setSampleDataList(sampleDataResponse.sampleDataList) @@ -254,9 +253,19 @@ const SampleApi = () => { return (
- - - +
+ +
+ + + +
diff --git a/apps/dashboard/web/polaris_web/web/src/util/func.js b/apps/dashboard/web/polaris_web/web/src/util/func.js index 8e902ff39a..7e818977cb 100644 --- a/apps/dashboard/web/polaris_web/web/src/util/func.js +++ b/apps/dashboard/web/polaris_web/web/src/util/func.js @@ -1067,6 +1067,13 @@ getSizeOfFile(bytes) { } return duration.trim(); }, + handleKeyPress (event, funcToCall) { + const enterKeyPressed = event.keyCode === 13; + if (enterKeyPressed) { + event.preventDefault(); + funcToCall(); + } + } } export default func \ No newline at end of file diff --git a/apps/testing/src/main/java/com/akto/test_editor/execution/VariableResolver.java b/apps/testing/src/main/java/com/akto/test_editor/execution/VariableResolver.java index 15906b8105..9fabbdfca9 100644 --- a/apps/testing/src/main/java/com/akto/test_editor/execution/VariableResolver.java +++ b/apps/testing/src/main/java/com/akto/test_editor/execution/VariableResolver.java @@ -26,26 +26,25 @@ public static String resolveExpression(Map varMap, String expres Pattern pattern = Pattern.compile("\\$\\{[^}]*\\}"); Matcher matcher = pattern.matcher(expression); - if (matcher.find()) { + while (matcher.find()) { try { String match = matcher.group(0); match = match.substring(2, match.length()); match = match.substring(0, match.length() - 1); Object val = getValue(varMap, match); String valString = val.toString(); - expression = expression.replaceAll("(\\$\\{[^}]*\\})", valString); + expression = expression.replaceFirst("(\\$\\{[^}]*\\})", valString); } catch (Exception e) { return expression; } + } + + Object val = getValue(varMap, expression); + if (val == null) { + return expression; } else { - Object val = getValue(varMap, expression); - if (val == null) { - return expression; - } else { - return val.toString(); - } + return val.toString(); } - return expression; } diff --git a/apps/testing/src/test/java/com/akto/test_editor/execution/TestVariableResolver.java b/apps/testing/src/test/java/com/akto/test_editor/execution/TestVariableResolver.java new file mode 100644 index 0000000000..edc6aac402 --- /dev/null +++ b/apps/testing/src/test/java/com/akto/test_editor/execution/TestVariableResolver.java @@ -0,0 +1,47 @@ +package com.akto.test_editor.execution; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static junit.framework.TestCase.assertEquals; + +public class TestVariableResolver { + + @Test + public void testResolveExpression() { + Map varMap = new HashMap<>(); + varMap.put("var1", "user1"); + varMap.put("var2", "user2"); + String result = VariableResolver.resolveExpression(varMap, "${var1}"); + assertEquals("user1", result); + result = VariableResolver.resolveExpression(varMap, "var1"); + assertEquals("user1", result); + + result = VariableResolver.resolveExpression(varMap, "${var1}!!!"); + assertEquals("user1!!!", result); + result = VariableResolver.resolveExpression(varMap, "var1!!!"); + assertEquals("var1!!!", result); + + result = VariableResolver.resolveExpression(varMap, "${var1}${var2}"); + assertEquals("user1user2", result); + result = VariableResolver.resolveExpression(varMap, "var1${var2}"); + assertEquals("var1user2", result); + + result = VariableResolver.resolveExpression(varMap, "${var1}&${var2}"); + assertEquals("user1&user2", result); + result = VariableResolver.resolveExpression(varMap, "var1&${var2}"); + assertEquals("var1&user2", result); + + result = VariableResolver.resolveExpression(varMap, "${var3}"); + assertEquals("${var3}", result); + + result = VariableResolver.resolveExpression(varMap, "${var1}${var1}"); + assertEquals("user1user1", result); + + result = VariableResolver.resolveExpression(varMap, "akto"); + assertEquals("akto", result); + } + +}