From 3ef1e944e298642fa3bfc6bb4fae4d49c0deb487 Mon Sep 17 00:00:00 2001 From: Teodora Sandu Date: Mon, 18 Mar 2024 13:56:49 +0000 Subject: [PATCH] feat: add data flow interaction --- .../SuggestionDescriptionPanelFromLS.kt | 64 +++++++++++++++++++ .../SuggestionDescriptionPanelFromLSTest.kt | 2 - 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/io/snyk/plugin/ui/toolwindow/panels/SuggestionDescriptionPanelFromLS.kt b/src/main/kotlin/io/snyk/plugin/ui/toolwindow/panels/SuggestionDescriptionPanelFromLS.kt index 65061eede..3d8cd2075 100644 --- a/src/main/kotlin/io/snyk/plugin/ui/toolwindow/panels/SuggestionDescriptionPanelFromLS.kt +++ b/src/main/kotlin/io/snyk/plugin/ui/toolwindow/panels/SuggestionDescriptionPanelFromLS.kt @@ -1,9 +1,13 @@ package io.snyk.plugin.ui.toolwindow.panels import com.intellij.icons.AllIcons +import com.intellij.openapi.application.ApplicationManager import com.intellij.ui.HyperlinkLabel import com.intellij.ui.ScrollPaneFactory import com.intellij.ui.components.JBTabbedPane +import com.intellij.ui.jcef.JBCefApp +import com.intellij.ui.jcef.JBCefBrowserBuilder +import com.intellij.ui.jcef.JBCefJSQuery import com.intellij.uiDesigner.core.GridConstraints import com.intellij.uiDesigner.core.GridLayoutManager import com.intellij.util.ui.JBInsets @@ -21,6 +25,9 @@ import io.snyk.plugin.ui.getJBCefBrowserIfSupported import io.snyk.plugin.ui.panelGridConstraints import io.snyk.plugin.ui.toolwindow.SnykToolWindowPanel import io.snyk.plugin.ui.wrapWithScrollPane +import org.cef.browser.CefBrowser +import org.cef.browser.CefFrame +import org.cef.handler.CefLoadHandlerAdapter import snyk.common.lsp.DataFlow import snyk.common.lsp.ScanIssue import java.awt.BorderLayout @@ -46,6 +53,28 @@ class SuggestionDescriptionPanelFromLS( val project = snykCodeFile.project private val unexpectedErrorMessage = "Snyk encountered an issue while rendering the vulnerability description. Please try again, or contact support if the problem persists. We apologize for any inconvenience caused."; + + fun openFile(value: String): JBCefJSQuery.Response { + var values = value.replace("\n", "").split(":") + var filePath = values[0] + var startLine = values[1].toInt() + var endLine = values[2].toInt() + var startCharacter = values[3].toInt() + var endCharacter = values[4].toInt() + + ApplicationManager.getApplication().invokeLater { + val virtualFile = filePath.toVirtualFile() + val document = virtualFile.getDocument() + val startLineStartOffset = document?.getLineStartOffset(startLine) ?: 0 + val startOffset = startLineStartOffset + (startCharacter) + val endLineStartOffset = document?.getLineStartOffset(endLine) ?: 0 + val endOffset = endLineStartOffset + endCharacter - 1 + + navigateToSource(project, virtualFile, startOffset, endOffset) + } + + return JBCefJSQuery.Response("success") + } init { if (pluginSettings().isGlobalIgnoresFeatureEnabled && issue.additionalData.details != null) { val (jbCefBrowser, jbCefBrowserUrl) = getJBCefBrowserIfSupported() @@ -54,6 +83,41 @@ class SuggestionDescriptionPanelFromLS( this.add(wrapWithScrollPane(statePanel), BorderLayout.CENTER) SnykBalloonNotificationHelper.showError(unexpectedErrorMessage, null) } else { + val cefClient = JBCefApp.getInstance().createClient() + val jbCefBrowser = JBCefBrowserBuilder().setClient(cefClient).setEnableOpenDevToolsMenuItem(true).build() + + val openFileQuery = JBCefJSQuery.create(jbCefBrowser) + + val loadHandler = object : CefLoadHandlerAdapter() { + override fun onLoadEnd(browser: CefBrowser, frame: CefFrame, httpStatusCode: Int) { + if (frame.isMain) { + cefClient.setProperty("JS_QUERY_POOL_SIZE", 1) + openFileQuery.addHandler { openFile(it) } + + browser.executeJavaScript( + "window.openFileQuery = function(value) {" + + openFileQuery.inject("value") + + "};", + browser.url, 0 + ); + + browser.executeJavaScript( + """ + const dataFlowFilePaths = document.getElementsByClassName('data-flow-filepath') + for (let i = 0; i < dataFlowFilePaths.length; i++) { + const dataFlowFilePath = dataFlowFilePaths[i] + dataFlowFilePath.addEventListener('click', function (e) { + e.preventDefault() + window.openFileQuery(dataFlowFilePath.getAttribute("file-path")+":"+dataFlowFilePath.getAttribute("start-line")+":"+dataFlowFilePath.getAttribute("end-line")+":"+dataFlowFilePath.getAttribute("start-character")+":"+dataFlowFilePath.getAttribute("end-character")); + }); + }""", + browser.url, 0 + ); + } + } + } + cefClient.addLoadHandler(loadHandler, jbCefBrowser.cefBrowser) + val panel = JPanel() panel.add(jbCefBrowser.component, BorderLayout()) this.add( diff --git a/src/test/kotlin/io/snyk/plugin/ui/toolwindow/SuggestionDescriptionPanelFromLSTest.kt b/src/test/kotlin/io/snyk/plugin/ui/toolwindow/SuggestionDescriptionPanelFromLSTest.kt index 13bd831de..0ce87f235 100644 --- a/src/test/kotlin/io/snyk/plugin/ui/toolwindow/SuggestionDescriptionPanelFromLSTest.kt +++ b/src/test/kotlin/io/snyk/plugin/ui/toolwindow/SuggestionDescriptionPanelFromLSTest.kt @@ -16,8 +16,6 @@ import io.snyk.plugin.resetSettings import io.snyk.plugin.snykcode.core.SnykCodeFile import io.snyk.plugin.ui.getJBCefBrowserIfSupported import io.snyk.plugin.ui.toolwindow.panels.SuggestionDescriptionPanelFromLS -import org.cef.browser.CefBrowserFactory -import org.cef.browser.CefRequestContext import org.eclipse.lsp4j.Position import org.eclipse.lsp4j.Range import org.junit.Before