|
1 | 1 | package io.snyk.languageserver.protocolextension;
|
2 | 2 |
|
| 3 | +import static io.snyk.eclipse.plugin.domain.ProductConstants.DIAGNOSTIC_SOURCE_SNYK_CODE; |
3 | 4 | import static io.snyk.eclipse.plugin.domain.ProductConstants.DISPLAYED_CODE_QUALITY;
|
4 | 5 | import static io.snyk.eclipse.plugin.domain.ProductConstants.DISPLAYED_CODE_SECURITY;
|
5 | 6 | import static io.snyk.eclipse.plugin.domain.ProductConstants.LSP_SOURCE_TO_SCAN_PARAMS;
|
|
22 | 23 | import static io.snyk.eclipse.plugin.views.snyktoolview.ISnykToolView.getPlural;
|
23 | 24 |
|
24 | 25 | import java.io.File;
|
| 26 | +import java.io.UnsupportedEncodingException; |
25 | 27 | import java.net.URI;
|
| 28 | +import java.net.URISyntaxException; |
| 29 | +import java.net.URLDecoder; |
26 | 30 | import java.nio.file.InvalidPathException;
|
27 | 31 | import java.nio.file.Path;
|
28 | 32 | import java.nio.file.Paths;
|
29 | 33 | import java.util.ArrayList;
|
30 | 34 | import java.util.Arrays;
|
31 | 35 | import java.util.Collections;
|
| 36 | +import java.util.HashMap; |
32 | 37 | import java.util.HashSet;
|
33 | 38 | import java.util.List;
|
| 39 | +import java.util.Map; |
34 | 40 | import java.util.Set;
|
35 | 41 | import java.util.concurrent.CompletableFuture;
|
36 | 42 | import java.util.concurrent.ExecutionException;
|
|
47 | 53 | import org.eclipse.lsp4e.LSPEclipseUtils;
|
48 | 54 | import org.eclipse.lsp4e.LanguageClientImpl;
|
49 | 55 | import org.eclipse.lsp4j.ProgressParams;
|
| 56 | +import org.eclipse.lsp4j.ShowDocumentParams; |
| 57 | +import org.eclipse.lsp4j.ShowDocumentResult; |
50 | 58 | import org.eclipse.lsp4j.WorkDoneProgressCreateParams;
|
51 | 59 | import org.eclipse.lsp4j.WorkDoneProgressKind;
|
52 | 60 | import org.eclipse.lsp4j.WorkDoneProgressNotification;
|
@@ -116,8 +124,8 @@ public class SnykExtendedLanguageClient extends LanguageClientImpl {
|
116 | 124 |
|
117 | 125 | public SnykExtendedLanguageClient() {
|
118 | 126 | super();
|
119 |
| - //TODO, fix this; Identifies a possible unsafe usage of a static field. |
120 |
| - instance = this; //NOPMD |
| 127 | + // TODO, fix this; Identifies a possible unsafe usage of a static field. |
| 128 | + instance = this; // NOPMD |
121 | 129 | om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
122 | 130 | registerPluginInstalledEventTask();
|
123 | 131 | registerRefreshFeatureFlagsTask();
|
@@ -384,16 +392,96 @@ public void snykScan(SnykScanParam param) {
|
384 | 392 | this.toolView.refreshBrowser(param.getStatus());
|
385 | 393 | }
|
386 | 394 |
|
| 395 | + @JsonNotification(value = LsConstants.SNYK_FOLDER_CONFIG) |
| 396 | + public void folderConfig(FolderConfigsParam folderConfigParam) { |
| 397 | + List<FolderConfig> folderConfigs = folderConfigParam != null ? folderConfigParam.getFolderConfigs() : List.of(); |
| 398 | + CompletableFuture.runAsync(() -> FolderConfigs.getInstance().addAll(folderConfigs)); |
| 399 | + } |
| 400 | + |
387 | 401 | @JsonNotification(value = LsConstants.SNYK_SCAN_SUMMARY)
|
388 | 402 | public void updateSummaryPanel(SummaryPanelParams summary) {
|
389 | 403 | openToolView();
|
390 | 404 | this.toolView.updateSummary(summary.getSummary());
|
391 | 405 | }
|
392 | 406 |
|
393 |
| - @JsonNotification(value = LsConstants.SNYK_FOLDER_CONFIG) |
394 |
| - public void folderConfig(FolderConfigsParam folderConfigParam) { |
395 |
| - List<FolderConfig> folderConfigs = folderConfigParam != null ? folderConfigParam.getFolderConfigs() : List.of(); |
396 |
| - CompletableFuture.runAsync(() -> FolderConfigs.getInstance().addAll(folderConfigs)); |
| 407 | + @Override |
| 408 | + public CompletableFuture<ShowDocumentResult> showDocument(ShowDocumentParams params) { |
| 409 | + URI uri; |
| 410 | + try { |
| 411 | + uri = new URI(params.getUri()); |
| 412 | + } catch (URISyntaxException e) { |
| 413 | + SnykLogger.logError(e); |
| 414 | + return null; |
| 415 | + } |
| 416 | + |
| 417 | + String scheme = uri.getScheme(); |
| 418 | + String product = getDecodedParam(uri, "product"); |
| 419 | + String action = getDecodedParam(uri, "action"); |
| 420 | + String issueId = getDecodedParam(uri, "issueId"); |
| 421 | + |
| 422 | + if (!"snyk".equals(scheme)) { |
| 423 | + SnykLogger.logInfo(String.format("Invalid URI: expected 'snyk' scheme but got %s", scheme)); |
| 424 | + } else if (!DIAGNOSTIC_SOURCE_SNYK_CODE.equals(product)) { |
| 425 | + SnykLogger.logInfo(String.format("Invalid URI: expected '{}' product but got %s", |
| 426 | + DIAGNOSTIC_SOURCE_SNYK_CODE, product)); |
| 427 | + } else if (!"showInDetailPanel".equals(action)) { |
| 428 | + SnykLogger.logInfo(String.format("Invalid URI: expected 'showInDetailPanel' action but got %s", action)); |
| 429 | + } else if (issueId.isEmpty()) { |
| 430 | + SnykLogger.logInfo(String.format("Invalid URI: 'issueId' empty")); |
| 431 | + } |
| 432 | + |
| 433 | + if (scheme.equals("snyk") && product.equals(DIAGNOSTIC_SOURCE_SNYK_CODE) |
| 434 | + && action.equals("showInDetailPanel")) { |
| 435 | + return CompletableFuture.supplyAsync(() -> { |
| 436 | + |
| 437 | + Issue issue = getIssueFromCache(uri); |
| 438 | + this.toolView.selectTreeNode(issue, product); |
| 439 | + return new ShowDocumentResult(true); |
| 440 | + }); |
| 441 | + } else { |
| 442 | + SnykLogger.logInfo(String.format("Invalid URI: scheme=%s, product=%s, action=%s", scheme, product, action)); |
| 443 | + return super.showDocument(params); |
| 444 | + } |
| 445 | + } |
| 446 | + |
| 447 | + public Issue getIssueFromCache(URI uri) { |
| 448 | + String filePath = uri.getPath(); |
| 449 | + String issueId = getDecodedParam(uri, "issueId"); |
| 450 | + |
| 451 | + SnykIssueCache issueCache = getIssueCache(filePath); |
| 452 | + return issueCache.getCodeSecurityIssuesForPath(filePath).stream().filter(i -> i.id().equals(issueId)) |
| 453 | + .findFirst().orElse(null); |
| 454 | + } |
| 455 | + |
| 456 | + public String getDecodedParam(URI uri, String paramName) { |
| 457 | + Map<String, String> paramMap = parseQueryString(uri.getQuery()); |
| 458 | + |
| 459 | + try { |
| 460 | + return URLDecoder.decode(paramMap.get(paramName), "UTF-8"); |
| 461 | + } catch (UnsupportedEncodingException e) { |
| 462 | + SnykLogger.logError(e); |
| 463 | + } |
| 464 | + return null; |
| 465 | + } |
| 466 | + |
| 467 | + private static Map<String, String> parseQueryString(String queryString) { |
| 468 | + Map<String, String> paramMap = new HashMap<>(); |
| 469 | + |
| 470 | + for (String param : queryString.split("&")) { |
| 471 | + if (!param.isEmpty()) { |
| 472 | + String[] keyValue = param.split("="); |
| 473 | + |
| 474 | + if (keyValue.length == 2) { |
| 475 | + try { |
| 476 | + paramMap.put(keyValue[0], URLDecoder.decode(keyValue[1], "UTF-8")); |
| 477 | + } catch (UnsupportedEncodingException e) { |
| 478 | + SnykLogger.logError(e); |
| 479 | + } |
| 480 | + } |
| 481 | + } |
| 482 | + } |
| 483 | + |
| 484 | + return paramMap; |
397 | 485 | }
|
398 | 486 |
|
399 | 487 | private void openToolView() {
|
@@ -473,7 +561,7 @@ public String getCountsSuffix(ProductTreeNode productTreeNode, SnykIssueCache is
|
473 | 561 | high, medium, low);
|
474 | 562 | }
|
475 | 563 |
|
476 |
| - private SnykIssueCache getIssueCache(String filePath) { |
| 564 | + public SnykIssueCache getIssueCache(String filePath) { |
477 | 565 | var issueCache = IssueCacheHolder.getInstance().getCacheInstance(Paths.get(filePath));
|
478 | 566 | if (issueCache == null) {
|
479 | 567 | throw new IllegalArgumentException("No issue cache for param possible");
|
@@ -548,11 +636,11 @@ private void populateFileAndIssueNodes(ProductTreeNode productTreeNode, SnykIssu
|
548 | 636 |
|
549 | 637 | if (issuesList.isEmpty())
|
550 | 638 | continue;
|
551 |
| - |
552 |
| - FileTreeNode fileNode = new FileTreeNode(fileName); //NOPMD |
| 639 | + |
| 640 | + FileTreeNode fileNode = new FileTreeNode(fileName); // NOPMD |
553 | 641 | toolView.addFileNode(productTreeNode, fileNode);
|
554 | 642 | for (Issue issue : issuesList) {
|
555 |
| - toolView.addIssueNode(fileNode, new IssueTreeNode(issue)); //NOPMD |
| 643 | + toolView.addIssueNode(fileNode, new IssueTreeNode(issue)); // NOPMD |
556 | 644 | }
|
557 | 645 | }
|
558 | 646 | }
|
|
0 commit comments