'use strict' ; import * as yaml from 'js-yaml' ; import * as vscode from 'vscode' ; import * as fs from 'fs-extra' ; import { Reporter } from '../util/Reporter' ; import { UserInputUtil , IBlockchainQuickPickItem } from './UserInputUtil' ; import { VSCodeBlockchainOutputAdapter } from '../logging/VSCodeBlockchainOutputAdapter' ; import { ExtensionCommands } from '../../ExtensionCommands' ; import { FabricCertificateAuthorityFactory } from '../fabric/FabricCertificateAuthorityFactory' ; import { WalletTreeItem } from '../explorer/wallets/WalletTreeItem' ; import { FabricGatewayHelper } from '../fabric/FabricGatewayHelper' ; import { FabricWalletRegistryEntry , IFabricCertificateAuthority , IFabricWallet , IFabricWalletGenerator , LogType , FabricEnvironmentRegistryEntry , FabricEnvironmentRegistry , FabricGatewayRegistryEntry , FabricWalletGeneratorFactory , FabricNode } from 'ibm-blockchain-platform-common' ; import { EnvironmentFactory } from '../fabric/environments/EnvironmentFactory' ; import { LocalMicroEnvironment } from '../fabric/environments/LocalMicroEnvironment' ; export async function addWalletIdentity ( walletItem , mspid ) { const outputAdapter = VSCodeBlockchainOutputAdapter . instance ( ) ; outputAdapter . log ( LogType . INFO , undefined , 'addWalletIdentity' ) ; const fabricWalletGenerator = FabricWalletGeneratorFactory . getFabricWalletGenerator ( ) ; let wallet ; let walletRegistryEntry ; if ( walletItem ) { if ( walletItem instanceof WalletTreeItem ) { walletRegistryEntry = walletItem . registryEntry ; } else { walletRegistryEntry = walletItem ; } wallet = await fabricWalletGenerator . getWallet ( walletRegistryEntry ) ; } else { const chosenWallet = await UserInputUtil . showWalletsQuickPickBox ( 'Choose a wallet to add identity to' , false , true ) as IBlockchainQuickPickItem < FabricWalletRegistryEntry > ; if ( ! chosenWallet ) { return ; } wallet = await fabricWalletGenerator . getWallet ( chosenWallet . data ) ; walletRegistryEntry = chosenWallet . data ; } let isManagedWallet ; if ( walletRegistryEntry && walletRegistryEntry . managedWallet ) { isManagedWallet = true ; } else { isManagedWallet = false ; } let environmentEntry ; if ( isManagedWallet ) { environmentEntry = await FabricEnvironmentRegistry . instance ( ) . get ( walletRegistryEntry . fromEnvironment ) ; const chosenOrg = await UserInputUtil . showOrgQuickPick ( `Select the organization which the identity belongs to` , environmentEntry ) ; if ( ! chosenOrg ) { return ; } mspid = chosenOrg . data . msp_id ; } else if ( ! mspid ) { mspid = await UserInputUtil . showInputBox ( 'Enter MSPID' ) ; if ( ! mspid ) { return ; } } let certificate ; let privateKey ; let certificatePath ; let privateKeyPath ; const addIdentityMethod = await UserInputUtil . addIdentityMethod ( isManagedWallet ) ; if ( ! addIdentityMethod ) { return ; } let identityName ; try { if ( addIdentityMethod === UserInputUtil . ADD_CERT_KEY_OPTION ) { identityName = await UserInputUtil . showInputBox ( 'Provide a name for the identity' ) ; const identityValid = await checkIdentityName ( identityName , wallet ) ; if ( ! identityValid ) { return ; } const certKey = await UserInputUtil . getCertKey ( ) ; if ( ! certKey ) { return ; } certificatePath = certKey . certificatePath ; privateKeyPath = certKey . privateKeyPath ; } else if ( addIdentityMethod === UserInputUtil . ADD_JSON_ID_OPTION ) { const openDialogOptions = { canSelectFiles : true , canSelectFolders : false , canSelectMany : false , openLabel : 'Select' , filters : { Identity : [ 'json' ] } } ; const jsonIdentityPath = await UserInputUtil . browse ( 'Browse for a JSON identity file' , UserInputUtil . BROWSE_LABEL , openDialogOptions , true ) as vscode . Uri ; if ( ! jsonIdentityPath ) { return ; } const name = 'name' ; const certProperty = 'cert' ; const privateKeyProperty = 'private_key' ; const jsonIdentityContents = await fs . readFile ( jsonIdentityPath . fsPath , 'utf8' ) ; const jsonIdentity = JSON . parse ( jsonIdentityContents ) ; if ( jsonIdentity [ certProperty ] && jsonIdentity [ privateKeyProperty ] ) { if ( ! jsonIdentity [ name ] ) { identityName = await UserInputUtil . showInputBox ( 'Provide a name for the identity' ) ; } else { identityName = jsonIdentity [ name ] ; } const identityValid = await checkIdentityName ( identityName , wallet ) ; if ( ! identityValid ) { return ; } certificate = Buffer . from ( jsonIdentity [ certProperty ] , 'base64' ) . toString ( ) ; privateKey = Buffer . from ( jsonIdentity [ privateKeyProperty ] , 'base64' ) . toString ( ) ; } else { throw new Error ( `JSON file missing properties \"${ certProperty }\" or \"${ privateKeyProperty }\"` ) ; } } else { let gatewayRegistryEntry ; identityName = await UserInputUtil . showInputBox ( 'Provide a name for the identity' ) ; const identityValid = await checkIdentityName ( identityName , wallet ) ; if ( ! identityValid ) { return ; } if ( isManagedWallet ) { let environment = EnvironmentFactory . getEnvironment ( environmentEntry ) as LocalMicroEnvironment ; let isRunning = await environment . isRunning ( ) ; if ( ! isRunning ) { await vscode . commands . executeCommand ( ExtensionCommands . START_FABRIC , environmentEntry ) ; environment = EnvironmentFactory . getEnvironment ( environmentEntry ) as LocalMicroEnvironment ; isRunning = await environment . isRunning ( ) ; if ( ! isRunning ) { return ; } } } const chosenEntry = await UserInputUtil . showGatewayQuickPickBox ( 'Choose a gateway to enroll the identity with' , false , true , undefined , walletRegistryEntry . fromEnvironment ) as IBlockchainQuickPickItem < FabricGatewayRegistryEntry > ; if ( ! chosenEntry ) { return ; } gatewayRegistryEntry = chosenEntry . data ; const enrollIdSecret = await UserInputUtil . getEnrollIdSecret ( ) ; if ( ! enrollIdSecret ) { return ; } const enrollmentID = enrollIdSecret . enrollmentID ; const enrollmentSecret = enrollIdSecret . enrollmentSecret ; const certificateAuthority = FabricCertificateAuthorityFactory . createCertificateAuthority ( ) ; const connectionProfilePath = await FabricGatewayHelper . getConnectionProfilePath ( gatewayRegistryEntry ) ; const connectionProfileFile = await fs . readFile ( connectionProfilePath , 'utf8' ) ; let connectionProfile ; if ( connectionProfilePath . endsWith ( '.json' ) ) { connectionProfile = JSON . parse ( connectionProfileFile ) ; } else { connectionProfile = yaml . safeLoad ( connectionProfileFile ) ; } let caKeys ; if ( connectionProfile . certificateAuthorities ) { caKeys = Object . keys ( connectionProfile . certificateAuthorities ) ; } if ( ! caKeys || caKeys . length === 0 ) { throw new Error ( 'No certificate authorities found in the connection profile' ) ; } let caUrl ; let caName ; if ( caKeys . length > 1 ) { const showMoreCAs = await UserInputUtil . showQuickPickCA ( caKeys ) ; if ( ! showMoreCAs ) { return ; } else { caUrl = connectionProfile . certificateAuthorities [ showMoreCAs ] . url ; caName = connectionProfile . certificateAuthorities [ showMoreCAs ] . caName ; } } else { caUrl = connectionProfile . certificateAuthorities [ caKeys [ 0 ] ] . url ; caName = connectionProfile . certificateAuthorities [ caKeys [ 0 ] ] . caName ; } const enrollment = await certificateAuthority . enroll ( caUrl , enrollmentID , enrollmentSecret , caName ) ; certificate = enrollment . certificate ; privateKey = enrollment . privateKey ; } if ( certificatePath && privateKeyPath ) { certificate = await fs . readFile ( certificatePath , 'utf8' ) ; privateKey = await fs . readFile ( privateKeyPath , 'utf8' ) ; } await wallet . importIdentity ( certificate , privateKey , identityName , mspid ) ; } catch ( error ) { outputAdapter . log ( LogType . ERROR , `Unable to add identity to wallet: ${ error . message }` , `Unable to add identity to wallet: ${ error . toString ( ) }` ) ; return ; } await vscode . commands . executeCommand ( ExtensionCommands . REFRESH_WALLETS ) ; outputAdapter . log ( LogType . SUCCESS , 'Successfully added identity' , `Successfully added identity to wallet` ) ; if ( addIdentityMethod === UserInputUtil . ADD_CERT_KEY_OPTION ) { Reporter . instance ( ) . sendTelemetryEvent ( 'addWalletIdentityCommand' , { method : 'Certificate' } ) ; } else if ( addIdentityMethod === UserInputUtil . ADD_JSON_ID_OPTION ) { Reporter . instance ( ) . sendTelemetryEvent ( 'addWalletIdentityCommand' , { method : 'json' } ) ; } else { Reporter . instance ( ) . sendTelemetryEvent ( 'addWalletIdentityCommand' , { method : 'enrollmentID' } ) ; } return identityName ; } async function checkIdentityName ( identityName , wallet ) { if ( ! identityName ) { VSCodeBlockchainOutputAdapter . instance ( ) . log ( LogType . ERROR , `An identity name cannot be empty` ) ; return false ; } const exists = await wallet . exists ( identityName ) ; if ( exists ) { VSCodeBlockchainOutputAdapter . instance ( ) . log ( LogType . ERROR , `An identity called ${ identityName } already exists` ) ; return false ; } return true ; }