Skip to content
This repository has been archived by the owner on Jan 31, 2023. It is now read-only.

Commit

Permalink
Ask for api key and secret when importing nodes from Ops Tools
Browse files Browse the repository at this point in the history
Signed-off-by: Leonor Quintais <lquintai@uk.ibm.com>
  • Loading branch information
lquintai committed Dec 2, 2019
1 parent 9091ec8 commit f5e0fdc
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 56 deletions.
53 changes: 29 additions & 24 deletions packages/blockchain-extension/extension/commands/UserInputUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ export class UserInputUtil {
static readonly ADD_GATEWAY_FROM_CCP: string = 'Create a gateway from a connection profile';
static readonly ADD_ENVIRONMENT_FROM_NODES: string = 'Add an environment from node definition files';
static readonly ADD_ENVIRONMENT_FROM_OPS_TOOLS: string = 'Add an environment from connecting to an ops tools instance';
static readonly ADD_CA_CERT_CHAIN: string = 'Provide the CA Certificate Chain file';
static readonly CONNECT_NO_CA_CERT_CHAIN: string = 'Proceed without certificate verification';

public static async showQuickPick(prompt: string, items: string[], canPickMany: boolean = false): Promise<string | string[]> {
const quickPickOptions: vscode.QuickPickOptions = {
Expand Down Expand Up @@ -910,27 +912,7 @@ export class UserInputUtil {
nodes = nodes.filter((node: FabricNode) => nodeTypefilter.indexOf(node.type) !== -1);
}

const quickPickItems: IBlockchainQuickPickItem<FabricNode>[] = [];
for (const _node of nodes) {
if (_node.type === FabricNodeType.ORDERER && _node.cluster_name) {
const foundItem: IBlockchainQuickPickItem<FabricNode> = quickPickItems.find((item: IBlockchainQuickPickItem<FabricNode>) => item.data.cluster_name === _node.cluster_name);

if (!foundItem) {
const quickPickItem: IBlockchainQuickPickItem<FabricNode> = { label: _node.cluster_name, data: _node };
if (showAsociatedIdentity && _node.wallet && _node.identity) {
quickPickItem.description = `Associated with identity: ${_node.identity} in wallet: ${_node.wallet}`;
}

quickPickItems.push(quickPickItem);
}
} else {
const quickPickItem: IBlockchainQuickPickItem<FabricNode> = { label: _node.name, data: _node };
if (showAsociatedIdentity && _node.wallet && _node.identity) {
quickPickItem.description = `Associated with identity: ${_node.identity} in wallet: ${_node.wallet}`;
}
quickPickItems.push(quickPickItem);
}
}
const quickPickItems: IBlockchainQuickPickItem<FabricNode>[] = UserInputUtil.selectNodesOneOrdererPerCluster(nodes, showAsociatedIdentity);

const quickPickOptions: vscode.QuickPickOptions = {
ignoreFocusOut: true,
Expand Down Expand Up @@ -1049,9 +1031,7 @@ export class UserInputUtil {
throw new Error('Error when importing nodes, no nodes found to choose from.');
}

const quickPickItems: IBlockchainQuickPickItem<FabricNode>[] = nodes.map((_node: FabricNode) => {
return { label: _node.name, data: _node };
});
const quickPickItems: IBlockchainQuickPickItem<FabricNode>[] = UserInputUtil.selectNodesOneOrdererPerCluster(nodes);

const quickPickOptions: vscode.QuickPickOptions = {
ignoreFocusOut: true,
Expand Down Expand Up @@ -1124,4 +1104,29 @@ export class UserInputUtil {

return tempQuickPickItems;
}

private static selectNodesOneOrdererPerCluster(nodes: FabricNode[], showAsociatedIdentity: boolean = false): IBlockchainQuickPickItem<FabricNode>[] {
const quickPickItems: IBlockchainQuickPickItem<FabricNode>[] = [];
for (const _node of nodes) {
if (_node.type === FabricNodeType.ORDERER && _node.cluster_name) {
const foundItem: IBlockchainQuickPickItem<FabricNode> = quickPickItems.find((item: IBlockchainQuickPickItem<FabricNode>) => item.data.cluster_name === _node.cluster_name);

if (!foundItem) {
const quickPickItem: IBlockchainQuickPickItem<FabricNode> = { label: _node.cluster_name, data: _node };
if (showAsociatedIdentity && _node.wallet && _node.identity) {
quickPickItem.description = `Associated with identity: ${_node.identity} in wallet: ${_node.wallet}`;
}

quickPickItems.push(quickPickItem);
}
} else {
const quickPickItem: IBlockchainQuickPickItem<FabricNode> = { label: _node.name, data: _node };
if (showAsociatedIdentity && _node.wallet && _node.identity) {
quickPickItem.description = `Associated with identity: ${_node.identity} in wallet: ${_node.wallet}`;
}
quickPickItems.push(quickPickItem);
}
}
return quickPickItems;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ import { VSCodeBlockchainOutputAdapter } from '../logging/VSCodeBlockchainOutput
import { LogType } from '../logging/OutputAdapter';
import { FabricEnvironmentRegistryEntry } from '../registries/FabricEnvironmentRegistryEntry';
import * as fs from 'fs-extra';
import * as https from 'https';
import * as path from 'path';
import { SettingConfigurations } from '../../configurations';
import { FabricNode } from '../fabric/FabricNode';
import { FabricNode, FabricNodeType } from '../fabric/FabricNode';
import { FabricEnvironment } from '../fabric/FabricEnvironment';
import { ExtensionCommands } from '../../ExtensionCommands';
import { FileSystemUtil } from '../util/FileSystemUtil';
Expand Down Expand Up @@ -102,7 +103,6 @@ export async function importNodesToEnvironment(environmentRegistryEntry: FabricE
}
}
} else {

const keytarany = getCoreNodeModule('keytar');
if (!keytar) {
throw new Error('Error importing the keytar module');
Expand All @@ -117,13 +117,51 @@ export async function importNodesToEnvironment(environmentRegistryEntry: FabricE
if (!apiKey) {
return;
}
const apiSecret: string = await UserInputUtil.showInputBox('Enter the api secret of the ops tools you want to connect to');
if (!apiSecret) {
return;
}

const api: string = url.replace(/\/$/, '') + GET_ALL_COMPONENTS;
let response: any;
const requestOptions: any = {
headers: { 'Content-Type': 'application/json' },
auth: { username: apiKey, password: apiSecret }
};
try {
const api: string = url.replace(/\/$/, '') + GET_ALL_COMPONENTS;
response = await Axios.get(api, {
headers: { Authorization: `Bearer ${apiKey}` }
});
try {
response = await Axios.get(api, requestOptions);
} catch (error) {
// This needs to be fixed - exactly what codes can we get that will require this behaviour?
if (error.code === 'DEPTH_ZERO_SELF_SIGNED_CERT') {
const certificateUsage: string = await UserInputUtil.showQuickPick('Unable to perform certificate verification. Please choose how to proceed', [UserInputUtil.ADD_CA_CERT_CHAIN, UserInputUtil.CONNECT_NO_CA_CERT_CHAIN]) as string;
if (!certificateUsage) {
return;
} else if (certificateUsage === UserInputUtil.ADD_CA_CERT_CHAIN) {
const quickPickItems: string[] = [UserInputUtil.BROWSE_LABEL];
const browseOptions: vscode.OpenDialogOptions = {
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,
openLabel: 'Select',
filters: {
Certificates: ['pem']
}
};
const certificatePath: vscode.Uri = await UserInputUtil.browse('Select CA certificate chain (.pem) file', quickPickItems, browseOptions, true) as vscode.Uri;
if (certificatePath === undefined) {
return;
}
const caCertificate: string = await fs.readFile(certificatePath.fsPath, 'utf8');
requestOptions.httpsAgent = new https.Agent({ ca: caCertificate });
} else {
requestOptions.httpsAgent = new https.Agent({ rejectUnauthorized: false });
}
response = await Axios.get(api, requestOptions);
} else {
throw error;
}
}

environmentRegistryEntry.url = url;

Expand Down Expand Up @@ -154,7 +192,9 @@ export async function importNodesToEnvironment(environmentRegistryEntry: FabricE
});

filteredData.forEach((node: FabricNode) => {
if (chosenNodesNames.indexOf(node.name) === -1) {
if (node.type === FabricNodeType.ORDERER && node.cluster_name) {
node.hidden = chosenNodesNames.indexOf(node.cluster_name) === -1;
} else if (chosenNodesNames.indexOf(node.name) === -1) {
node.hidden = true;
}
});
Expand All @@ -167,9 +207,9 @@ export async function importNodesToEnvironment(environmentRegistryEntry: FabricE
}

try {
await keytar.setPassword('blockchain-vscode-ext', url, apiKey);
await keytar.setPassword('blockchain-vscode-ext', url, `${apiKey}:${apiSecret}`);
} catch (error) {
throw new Error(`Unable to store API key securely in your keychain: ${error.message}`);
throw new Error(`Unable to store API key and API secret securely in your keychain: ${error.message}`);
}
}

Expand Down
Loading

0 comments on commit f5e0fdc

Please sign in to comment.