import * as http2 from 'http2' ; import { ComponentDetails , IJfrogClientConfig , IProxyConfig , ISummaryRequestModel , IXrayVersion , JfrogClient } from 'jfrog-client-js' ; import * as semver from 'semver' ; import { SemVer } from 'semver' ; import { URL } from 'url' ; import * as vscode from 'vscode' ; import { LogManager } from '../log/logManager' ; export class ConnectionUtils { private static readonly MINIMAL_XRAY_VERSION_SUPPORTED_FOR_GRAPH_SCAN : any = semver . coerce ( '3.29.0' ) ; private static readonly MINIMAL_XRAY_VERSION_SUPPORTED_FOR_CI : any = semver . coerce ( '3.21.2' ) ; private static readonly MINIMAL_XRAY_VERSION_SUPPORTED : any = semver . coerce ( '2.5.0' ) ; static readonly USER_AGENT : string = 'jfrog-vscode-extension/' + require ( '../../../package.json' ) . version ; see vscode . InputBoxOptions . validateInput param value returns public static validateUrl ( value ) { if ( ! value ) { return '' ; } let protocol ; let host ; try { let uri = new URL ( value ) ; protocol = uri . protocol ; host = uri . host ; } catch { } return protocol && host ? '' : 'Please enter a valid URL' ; } public static validateXrayUrl ( value ) { if ( ! value ) { return 'URL cannot be empty.' ; } return ConnectionUtils . validateUrl ( value ) ; } see vscode . InputBoxOptions . validateInput param value returns public static validateFieldNotEmpty ( value ) { return value ? '' : 'Value cannot be empty' ; } param rtUrl param username param password param accessToken public static async validateArtifactoryConnection ( rtUrl , username , password , accessToken ) { let jfrogClient = this . createJfrogClient ( '' , rtUrl , '' , username , password , accessToken ) ; return await jfrogClient . artifactory ( ) . system ( ) . ping ( ) ; } public static async isPlatformUrl ( url , username , password , accessToken ) { if ( ! url || url . endsWith ( '/xray' ) || url . endsWith ( '/xray/' ) ) { return false ; } let jfrogClient = this . createJfrogClient ( url , '' , '' , username , password , accessToken ) ; return await jfrogClient . xray ( ) . system ( ) . ping ( ) ; } returns param xrayUrl param username param password param accessToken public static async checkXrayConnectionAndPermissions ( xrayUrl , username , password , accessToken , prompt , logger ) { let jfrogClient = this . createJfrogClient ( '' , '' , xrayUrl , username , password , accessToken ) ; try { await ConnectionUtils . testComponentPermission ( jfrogClient ) ; let xrayVersion = await ConnectionUtils . testXrayVersion ( jfrogClient ) ; if ( prompt ) { vscode . window . showInformationMessage ( xrayVersion ) ; } else { logger . logMessage ( xrayVersion , 'DEBUG' ) ; } } catch ( error ) { if ( prompt ) { vscode . window . showErrorMessage ( ( < any > error ) . message || error , < vscode . MessageOptions > { modal : true } ) ; } else { logger . logMessage ( ( < any > error ) . message , 'DEBUG' ) ; } return Promise . resolve ( false ) ; } return Promise . resolve ( true ) ; } returns param rtUrl param username param password param accessToken public static async checkArtifactoryConnection ( rtUrl , username , password , accessToken , prompt , logger ) { const status = await ConnectionUtils . validateArtifactoryConnection ( rtUrl , username , password , accessToken ) ; let statusStr = 'failed.' ; if ( status ) { statusStr = 'success.' ; } const msg = 'Artifactory connection ' + statusStr ; if ( prompt ) { vscode . window . showInformationMessage ( msg ) ; } else { logger . logMessage ( msg , 'DEBUG' ) ; } return Promise . resolve ( status ) ; } public static async testXrayVersion ( jfrogClient ) { let xrayVersion = await this . getXrayVersion ( jfrogClient ) ; if ( ! ( await this . isXrayVersionCompatible ( xrayVersion , ConnectionUtils . MINIMAL_XRAY_VERSION_SUPPORTED ) ) ) { return Promise . reject ( 'Unsupported Xray version: ' + xrayVersion + ', version ' + ConnectionUtils . MINIMAL_XRAY_VERSION_SUPPORTED + ' or above is required.' ) ; } return Promise . resolve ( 'Successfully connected to Xray version: ' + xrayVersion ) ; } public static async testXrayVersionForScanGraph ( jfrogClient , logger ) { let xrayVersion = await this . getXrayVersion ( jfrogClient ) ; if ( ! ( await this . isXrayVersionCompatible ( xrayVersion , ConnectionUtils . MINIMAL_XRAY_VERSION_SUPPORTED_FOR_GRAPH_SCAN ) ) ) { logger . logMessage ( 'Unsupported Xray version for graph scan: ' + xrayVersion + ', version ' + ConnectionUtils . MINIMAL_XRAY_VERSION_SUPPORTED_FOR_GRAPH_SCAN + ' or above is required. Scanning dependencies without project support...' , 'DEBUG' ) ; return false ; } return true ; } public static async testXrayVersionForCi ( jfrogClient , logger ) { let xrayVersion = await this . getXrayVersion ( jfrogClient ) ; if ( ! ( await this . isXrayVersionCompatible ( xrayVersion , ConnectionUtils . MINIMAL_XRAY_VERSION_SUPPORTED_FOR_CI ) ) ) { logger . logMessage ( 'Unsupported Xray version for builds scan: ' + xrayVersion + ', version ' + ConnectionUtils . MINIMAL_XRAY_VERSION_SUPPORTED_FOR_CI + ' or above is required. Scanning builds without Xray results...' , 'WARN' ) ; return false ; } return true ; } public static async isXrayVersionCompatible ( curXrayVersion , minXrayVersion ) { if ( curXrayVersion !== 'Unknown' ) { let xraySemver = new semver . SemVer ( curXrayVersion ) ; return xraySemver . compare ( minXrayVersion ) >= 0 ; } return true ; } public static async getXrayVersion ( jfrogClient ) { let xrayVersion = await jfrogClient . xray ( ) . system ( ) . version ( ) ; return xrayVersion . xray_version ; } public static async testComponentPermission ( jfrogClient ) { let summaryRequest = { component_details : [ new ComponentDetails ( 'testComponent' ) ] } as ISummaryRequestModel ; try { await jfrogClient . xray ( ) . summary ( ) . component ( summaryRequest ) ; } catch ( error ) { if ( ! ( < any > error ) . response ) { return Promise . reject ( 'Could not connect to Xray: ' + error ) ; } let message = '' ; switch ( ( < any > error ) . response . status ) { case http2 . constants . HTTP_STATUS_UNAUTHORIZED : message = 'Please check your credentials.' ; break ; case http2 . constants . HTTP_STATUS_FORBIDDEN : message = "Please make sure that the user has 'View Components' permission in Xray." ; break ; } return Promise . reject ( ( < any > error ) . message + '. ' + message ) ; } return Promise . resolve ( ) ; } public static createJfrogClient ( platformUrl , artifactoryUrl , xrayUrl , username , password , accessToken ) { let clientConfig = { platformUrl : platformUrl , artifactoryUrl : artifactoryUrl , xrayUrl : xrayUrl , username : username , password : password , accessToken : accessToken , headers : { } , proxy : ConnectionUtils . getProxyConfig ( ) } as IJfrogClientConfig ; ConnectionUtils . addUserAgentHeader ( clientConfig ) ; ConnectionUtils . addProxyAuthHeader ( clientConfig ) ; return new JfrogClient ( clientConfig ) ; } public static addUserAgentHeader ( clientConfig ) { if ( clientConfig . headers ) { clientConfig . headers [ 'User-Agent' ] = ConnectionUtils . USER_AGENT ; } } public static addProxyAuthHeader ( clientConfig ) { if ( clientConfig . proxy ) { let proxyAuthHeader = vscode . workspace . getConfiguration ( ) . get ( 'http.proxyAuthorization' ) ; if ( proxyAuthHeader && clientConfig . headers ) { clientConfig . headers [ 'Proxy-Authorization' ] = proxyAuthHeader ; } } } public static getProxyConfig ( ) { let proxySupport = vscode . workspace . getConfiguration ( ) . get ( 'http.proxySupport' , 'override' ) ; if ( proxySupport === 'off' ) { return false ; } let proxyConfig = { } as IProxyConfig ; let httpProxy = vscode . workspace . getConfiguration ( ) . get ( 'http.proxy' ) ; if ( httpProxy ) { let proxyUri = new URL ( httpProxy ) ; proxyConfig . protocol = proxyUri . protocol ; proxyConfig . host = proxyUri . host ; if ( proxyUri . port ) { proxyConfig . port = + proxyUri . port ; } } return proxyConfig ; } }