Skip to content

Commit

Permalink
fix: Refresh IQ stuff when App ID is changed (#178)
Browse files Browse the repository at this point in the history
* Roll that beautiful bean footage

* Hello hello hello

* added functions for IQ url, user, and password to let those fields be dynamically reloaded as well

* added request service setter for username and utilized setters when changing IQ user and pw dynamically

* added dynamic settings change for the URL by adding a setter for the URL that also sets the agent

* initial attempt at a refactor to simplify config changes that would require modifying the iq request service

* Here we go

Co-authored-by: Artemie Jurgenson <[email protected]>
  • Loading branch information
DarthHater and Artemie Jurgenson authored Jan 21, 2021
1 parent 4f0968e commit 49a9028
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 22 deletions.
25 changes: 25 additions & 0 deletions ext-src/NexusExplorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { OssIndexComponentModel } from "./models/OssIndexComponentModel";
import { ComponentModel } from "./models/ComponentModel";
import { ComponentEntry } from "./models/ComponentEntry";
import { ILogger, Logger, LogLevel } from './utils/Logger';
import {NEXUS_IQ_SERVER_URL} from "./utils/Config";

export class NexusExplorerProvider implements vscode.TreeDataProvider<ComponentEntry> {
private editor?: vscode.TextEditor;
Expand Down Expand Up @@ -237,4 +238,28 @@ export class NexusExplorer {

this.nexusExplorerProvider.doRefresh();
}

public updateIQAppID(applicationID: string) {
if (this.componentModel instanceof IqComponentModel) {
this.componentModel.applicationPublicId = applicationID;

this.nexusExplorerProvider.doRefresh();
}
}

public refreshIQRequestService(options: RefreshOptions) {
if (this.componentModel instanceof IqComponentModel) {
if (options) {
this.componentModel.requestService.setOptions(options);

this.nexusExplorerProvider.doRefresh();
}
}
}
}

export interface RefreshOptions {
url: string,
username: string,
token: string
}
27 changes: 21 additions & 6 deletions ext-src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {url} from 'inspector';
import * as vscode from 'vscode';
import { NexusExplorer } from './NexusExplorer';
import { NEXUS_EXPLORER_DATA_SOURCE, NEXUS_IQ_PUBLIC_APPLICATION_ID, NEXUS_IQ_SERVER_URL, NEXUS_IQ_USERNAME, NEXUS_IQ_USER_PASSWORD } from './utils/Config';

export function activate(context: vscode.ExtensionContext) {

const explorer = new NexusExplorer(context);

// Listen to changes of the configuration, and if it's a change to the datasource, reload the dang thing
vscode.workspace.onDidChangeConfiguration((event) => {
let affected = event.affectsConfiguration("nexusExplorer.dataSource");
// Listen to changes of the configuration, and updates things if we need to
const eventConfigDisposable = vscode.workspace.onDidChangeConfiguration((event) => {
if (event.affectsConfiguration(NEXUS_EXPLORER_DATA_SOURCE)) {
explorer.switchComponentModel(vscode.workspace.getConfiguration().get(NEXUS_EXPLORER_DATA_SOURCE) as string);
}

if (event.affectsConfiguration(NEXUS_IQ_PUBLIC_APPLICATION_ID)) {
explorer.updateIQAppID(vscode.workspace.getConfiguration().get(NEXUS_IQ_PUBLIC_APPLICATION_ID) as string);
}

if (affected) {
let source = vscode.workspace.getConfiguration().get("nexusExplorer.dataSource") + "";
explorer.switchComponentModel(source);
if (event.affectsConfiguration(NEXUS_IQ_SERVER_URL) ||
event.affectsConfiguration(NEXUS_IQ_USERNAME) ||
event.affectsConfiguration(NEXUS_IQ_USER_PASSWORD)) {
explorer.refreshIQRequestService(
{ url: vscode.workspace.getConfiguration().get(NEXUS_IQ_SERVER_URL) as string,
username: vscode.workspace.getConfiguration().get(NEXUS_IQ_USERNAME) as string,
token: vscode.workspace.getConfiguration().get(NEXUS_IQ_USER_PASSWORD) as string}
)
}
});

context.subscriptions.push(eventConfigDisposable);
}
29 changes: 19 additions & 10 deletions ext-src/models/IqComponentModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ import { ILogger, LogLevel } from "../utils/Logger";
import { PackageType } from "../packages/PackageType";
import { CycloneDXSbomCreator } from "../cyclonedx/CycloneDXGenerator";
import { ReportResponse } from "../services/ReportResponse";
import {
NEXUS_EXPLORER_DATA_SOURCE,
NEXUS_IQ_MAX_EVAL_POLL_ATTEMPTS,
NEXUS_IQ_PUBLIC_APPLICATION_ID,
NEXUS_IQ_SERVER_URL,
NEXUS_IQ_STRICT_SSL,
NEXUS_IQ_USERNAME,
NEXUS_IQ_USER_PASSWORD } from "../utils/Config";

export class IqComponentModel implements ComponentModel {
components = new Array<ComponentEntry>();
Expand All @@ -33,22 +41,23 @@ export class IqComponentModel implements ComponentModel {
ComponentEntry
>();
requestService: RequestService;
dataSourceType: string;
applicationPublicId: string;
private logger: ILogger;

constructor(
options: ComponentModelOptions
) {
this.dataSourceType = options.configuration.get("nexusExplorer.dataSource", "ossindex");
let url = options.configuration.get("nexusIQ.serverUrl") + "";
let username = options.configuration.get("nexusIQ.username") + "";
let maximumEvaluationPollAttempts = parseInt(
options.configuration.get("nexusIQ.maximumEvaluationPollAttempts") + "", 10);
this.applicationPublicId = options.configuration.get("nexusIQ.applicationId") + "";
let password = options.configuration.get("nexusIQ.userPassword") + "";
let strictSSL = options.configuration.get("nexusIQ.strictSSL") as boolean;
this.applicationPublicId = options.configuration.get(NEXUS_IQ_PUBLIC_APPLICATION_ID) + "";

const url = options.configuration.get(NEXUS_IQ_SERVER_URL) + "";
const username = options.configuration.get(NEXUS_IQ_USERNAME) + "";
const maximumEvaluationPollAttempts = parseInt(
options.configuration.get(NEXUS_IQ_MAX_EVAL_POLL_ATTEMPTS) + "", 10);
const password = options.configuration.get(NEXUS_IQ_USER_PASSWORD) + "";
const strictSSL = options.configuration.get(NEXUS_IQ_STRICT_SSL) as boolean;

this.requestService = new IqRequestService(url, username, password, maximumEvaluationPollAttempts, strictSSL, options.logger);

this.logger = options.logger;
}

Expand All @@ -58,7 +67,7 @@ export class IqComponentModel implements ComponentModel {
}

private async performIqScan(): Promise<any> {
return new Promise((resolve, reject) => {
return new Promise<void>((resolve, reject) => {
try {
let componentContainer = new ComponentContainer(this.logger);

Expand Down
33 changes: 27 additions & 6 deletions ext-src/services/IqRequestService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import fetch from 'node-fetch';
import { Headers } from 'node-fetch';
import { RequestService } from "./RequestService";
import { RequestHelpers } from "./RequestHelpers";
import { Agent as HttpsAgent } from "https";
import { Agent as HttpsAgent, RequestOptions } from "https";
import { Agent } from 'http';
import { ILogger, LogLevel } from '../utils/Logger';
import { ThirdPartyAPIResponse } from './ThirdPartyApiResponse';
Expand All @@ -27,10 +27,11 @@ import { PackageURL } from 'packageurl-js';
import { VulnerabilityResponse } from './VulnerabilityResponse';
import { RemediationResponse } from './RemediationResponse';
import { ApplicationResponse } from './ApplicationReponse';
import { RefreshOptions } from '../NexusExplorer';

export class IqRequestService implements RequestService {
readonly evaluationPollDelayMs = 2000;
private agent: Agent;
private agent: Agent = this.getAgent(false, false);
applicationId: string = "";

constructor(
Expand All @@ -42,12 +43,32 @@ export class IqRequestService implements RequestService {
readonly logger: ILogger
)
{
if (url.endsWith("/")) {
this.url = url.replace(/\/$/, "");
this.setUrl(url);

this.logger.log(LogLevel.INFO, `Created new IQ Request Service at: `, url);
}

public setOptions(options: RefreshOptions) {
if (options.url) {
this.setUrl(options.url);
}
if (options.username) {
this.user = options.username;
}
if (options.token) {
this.password = options.token;
}
this.logger.log(LogLevel.TRACE, `Creating new IQ Request Service`, url);
}

private setUrl(url: string) {
this.logger.log(LogLevel.TRACE, `Setting IQ url to: `, this.url);

this.agent = this.getAgent(this.strictSSL, url.startsWith('https'));
this.url = url.replace(/\/$/, "");

this.agent = this.getAgent(
this.strictSSL,
this.url.startsWith('https')
);
}

public setPassword(password: string) {
Expand Down
2 changes: 2 additions & 0 deletions ext-src/services/RequestService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { VulnerabilityResponse } from './VulnerabilityResponse';
import { RemediationResponse } from './RemediationResponse';
import { ComponentDetails } from './ComponentDetails';
import { PackageURL } from 'packageurl-js';
import { RefreshOptions } from "../NexusExplorer";

export interface RequestService extends BaseRequestService {
getApplicationId(applicationPublicId: string): Promise<string>;
Expand All @@ -31,6 +32,7 @@ export interface RequestService extends BaseRequestService {
getVulnerabilityDetails(vulnID: string): Promise<VulnerabilityResponse>;
getRemediation(purl: string): Promise<RemediationResponse>;
showSelectedVersion(purl: string): Promise<ComponentDetails>
setOptions(options: RefreshOptions): void;
setPassword(password: string): void;
isPasswordSet(): boolean;
setApplicationId(s: string): void;
Expand Down
35 changes: 35 additions & 0 deletions ext-src/utils/Config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2019-present Sonatype, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const NEXUS_EXPLORER_BASE = "nexusExplorer";
const NEXUS_IQ_BASE = "nexusIQ";

const NEXUS_EXPLORER_DATA_SOURCE = NEXUS_EXPLORER_BASE.concat(".", "dataSource");
const NEXUS_IQ_SERVER_URL = NEXUS_IQ_BASE.concat(".", "serverUrl");
const NEXUS_IQ_USERNAME = NEXUS_IQ_BASE.concat(".", "username");
const NEXUS_IQ_MAX_EVAL_POLL_ATTEMPTS = NEXUS_IQ_BASE.concat(".", "maximumEvaluationPollAttempts");
const NEXUS_IQ_PUBLIC_APPLICATION_ID = NEXUS_IQ_BASE.concat(".", "applicationId");
const NEXUS_IQ_USER_PASSWORD = NEXUS_IQ_BASE.concat(".", "userPassword");
const NEXUS_IQ_STRICT_SSL = NEXUS_IQ_BASE.concat(".", "strictSSL");

export {
NEXUS_EXPLORER_DATA_SOURCE,
NEXUS_IQ_SERVER_URL,
NEXUS_IQ_USERNAME,
NEXUS_IQ_MAX_EVAL_POLL_ATTEMPTS,
NEXUS_IQ_PUBLIC_APPLICATION_ID,
NEXUS_IQ_USER_PASSWORD,
NEXUS_IQ_STRICT_SSL
};

0 comments on commit 49a9028

Please sign in to comment.