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

Ask for api key and secret when importing nodes from Ops Tools #1691

Merged
merged 1 commit into from
Dec 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 keytar: any = 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