Skip to content

Commit

Permalink
Merge pull request #1056 from halcyon-tech/change/debug_mode
Browse files Browse the repository at this point in the history
Change/debug mode
  • Loading branch information
worksofliam committed Feb 11, 2023
2 parents 1c501e2 + 3246ce3 commit 539c955
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 87 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -349,9 +349,9 @@
"default": "8005",
"description": "Port to connect to IBM i Debug Service."
},
"debugSecure": {
"debugIsSecure": {
"type": "boolean",
"default": true,
"default": false,
"description": "Used to determine if the client should connect securely or not."
},
"debugUpdateProductionFiles": {
Expand Down Expand Up @@ -786,12 +786,12 @@
},
{
"command": "code-for-ibmi.debug.setup.local",
"title": "Setup local certificate",
"title": "Import local certificate",
"category": "IBM i Debug"
},
{
"command": "code-for-ibmi.debug.start",
"title": "Start debug server",
"title": "Start debug service",
"category": "IBM i Debug"
},
{
Expand Down
4 changes: 2 additions & 2 deletions src/api/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export namespace ConnectionConfiguration {
autoSaveBeforeAction: boolean;
showDescInLibList: boolean;
debugPort: string;
debugSecure: boolean;
debugIsSecure: boolean;
debugUpdateProductionFiles: boolean;
debugEnableDebugTracing: boolean;
[name: string]: any;
Expand Down Expand Up @@ -105,7 +105,7 @@ export namespace ConnectionConfiguration {
autoSaveBeforeAction : (parameters.autoSaveBeforeAction === true),
showDescInLibList : (parameters.showDescInLibList === true),
debugPort: (parameters.debugPort || "8005"),
debugSecure: (parameters.debugSecure === true || parameters.debugSecure === undefined),
debugIsSecure: (parameters.debugIsSecure === true),
debugUpdateProductionFiles: (parameters.debugUpdateProductionFiles === true),
debugEnableDebugTracing: (parameters.debugEnableDebugTracing === true),
}
Expand Down
11 changes: 2 additions & 9 deletions src/api/debug/certificates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export function getKeystorePath() {
return path.posix.join(directory, pfxName);
}

export function getLocalCert(connection: IBMi) {
export function getLocalCertPath(connection: IBMi) {
const host = connection.currentHost;
return path.join(os.homedir(), `${host}_${crtName}`);
}
Expand Down Expand Up @@ -59,17 +59,10 @@ export async function setup(connection: IBMi) {

export async function checkLocalExists(connection: IBMi) {
try {
await fs.stat(getLocalCert(connection));
await fs.stat(getLocalCertPath(connection));
// TODO: if local exists, but it's out of date with the server? e.g. md5 is different for example
return true;
} catch (e) {
return false;
}
}

export function downloadToLocal(connection: IBMi) {
return connection.downloadFile(
getLocalCert(connection),
path.posix.join(directory, crtName)
);
}
152 changes: 85 additions & 67 deletions src/api/debug/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import path from "path";

import * as certificates from "./certificates";
import * as server from "./server";
import { copyFileSync } from "fs";

const debugExtensionId = `IBM.ibmidebug`;

Expand Down Expand Up @@ -158,26 +159,30 @@ export async function initialise(instance: Instance, context: ExtensionContext)
vscode.window.showInformationMessage(`Certificates already exist on the server.`);
remoteCertsOk = true;
} else {
const doSetup = await vscode.window.showInformationMessage(`Debug setup`, {
modal: true,
detail: `Debug certificates are not setup on the system. Continue with setup?`
}, `Continue`);

if (doSetup) {
try {
await certificates.setup(connection);
vscode.window.showInformationMessage(`Certificates successfully generated on server.`);
remoteCertsOk = true;
remoteCertsAreNew = true;
} catch (e: any) {
vscode.window.showErrorMessage(e.message || e);
}

}

const doSetup = await vscode.window.showInformationMessage(`Debug setup`, {
modal: true,
detail: `${remoteExists
? `Debug certificates already exist on this system! Running this setup will overwrite them, which will require the debug service to be restarted.`
: `Debug certificates are not setup on the system.`
} Continue with setup?`
}, `Continue`);

if (doSetup) {
try {
await certificates.setup(connection);
vscode.window.showInformationMessage(`Certificates successfully generated on server.`);
remoteCertsOk = true;
remoteCertsAreNew = true;
} catch (e: any) {
vscode.window.showErrorMessage(e.message || e);
}
}

if (remoteCertsOk) {
vscode.commands.executeCommand(`setContext`, remoteCertContext, true);
vscode.commands.executeCommand(`code-for-ibmi.debug.setup.local`, remoteCertsAreNew);
}
} else {
vscode.window.showErrorMessage(`Debug PTF not installed.`);
Expand All @@ -188,29 +193,49 @@ export async function initialise(instance: Instance, context: ExtensionContext)
}
}),

vscode.commands.registerCommand(`code-for-ibmi.debug.setup.local`, async (force: boolean = false) => {
vscode.commands.registerCommand(`code-for-ibmi.debug.setup.local`, async () => {
const connection = instance.connection;

if (connection) {
const ptfInstalled = await debugPTFInstalled();

if (ptfInstalled) {
const localExists = await certificates.checkLocalExists(connection);
let localCertsOk = false;

if (localExists && !force) {
localCertsOk = true;
vscode.window.showInformationMessage(`Debug certificates already exist locally. Skipping this step.`);
} else {
try {
await certificates.downloadToLocal(connection);
vscode.window.showInformationMessage(`Debug certificates successfully downloaded to local device.`);
localCertsOk = true;
} catch (e: any) {
vscode.window.showErrorMessage(`Failed to download new local debug certificate.`);
if (connection.config!.debugIsSecure) {
const selection = await vscode.window.showInformationMessage(
`Client certificate`,
{
modal: true,
detail: `To debug securely, a client certificate needs to be imported.`
},
`Import certificate`
);

if (selection === `Import certificate`) {
const selectedFile = await vscode.window.showOpenDialog({
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,
title: `Select client certificate`
});

if (selectedFile && selectedFile.length === 1) {
try {
copyFileSync(selectedFile[0].fsPath, certificates.getLocalCertPath(connection));
localCertsOk = true;
vscode.window.showInformationMessage(`Certificate imported.`);
} catch (e) {
vscode.window.showErrorMessage(`Failed to import local certificate.`);
}
}
}
} else {
vscode.window.showWarningMessage(`Certificates can only be imported when secure mode is enabled.`, `Open configuration`).then(result => {
if (result === `Open configuration`) {
vscode.commands.executeCommand(`code-for-ibmi.showAdditionalSettings`);
}
});
}

if (localCertsOk) {
vscode.commands.executeCommand(`setContext`, localCertContext, true);
}
Expand All @@ -228,44 +253,35 @@ export async function initialise(instance: Instance, context: ExtensionContext)
const remoteExists = await certificates.checkRemoteExists(connection);
if (remoteExists) {

const localExists = await certificates.checkLocalExists(connection);
if (localExists) {
vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async (progress) => {
vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async (progress) => {

let startupService = false;
let startupService = false;

progress.report({ increment: 20, message: `Checking if service is already running.` });
const isRunning = await server.isRunning(connection.config?.debugPort || "8005", instance.content!);
progress.report({ increment: 20, message: `Checking if service is already running.` });
const isRunning = await server.isRunning(connection.config?.debugPort || "8005", instance.content!);

if (isRunning) {
const confirmEndServer = await vscode.window.showInformationMessage(`Starting debug service`, {
detail: `Looks like the debug service is currently running. Do you want to end it to start a new instance?`,
modal: true
}, `End service`);
if (isRunning) {
const confirmEndServer = await vscode.window.showInformationMessage(`Starting debug service`, {
detail: `Looks like the debug service is currently running. Do you want to end it to start a new instance?`,
modal: true
}, `End service`);

if (confirmEndServer === `End service`) {
progress.report({ increment: 25, message: `Ending currently running service.` });
const endResult = await server.end(connection);
startupService = true;
}
} else {
if (confirmEndServer === `End service`) {
progress.report({ increment: 25, message: `Ending currently running service.` });
const endResult = await server.end(connection);
startupService = true;
}
} else {
startupService = true;
}

if (startupService) {
progress.report({ increment: 25, message: `Starting service up.` });
await server.startup(connection);
} else {
vscode.window.showInformationMessage(`Cancelled startup of debug service.`);
}
})

} else {
const localResult = await vscode.window.showErrorMessage(`Local debug certificate does not exist.`, `Setup`);
if (localResult === `Setup`) {
vscode.commands.executeCommand(`code-for-ibmi.debug.setup.local`);
if (startupService) {
progress.report({ increment: 25, message: `Starting service up.` });
await server.startup(connection);
} else {
vscode.window.showInformationMessage(`Cancelled startup of debug service.`);
}
}
})

} else {
vscode.commands.executeCommand(`code-for-ibmi.debug.setup.remote`);
Expand All @@ -288,12 +304,14 @@ export async function initialise(instance: Instance, context: ExtensionContext)
if (remoteCerts) {
vscode.commands.executeCommand(`setContext`, remoteCertContext, true);

const localExists = await certificates.checkLocalExists(instance.connection);
if (instance.connection.config!.debugIsSecure) {
const localExists = await certificates.checkLocalExists(instance.connection);

if (localExists) {
vscode.commands.executeCommand(`setContext`, localCertContext, true);
} else {
vscode.commands.executeCommand(`code-for-ibmi.debug.setup.local`);
if (localExists) {
vscode.commands.executeCommand(`setContext`, localCertContext, true);
} else {
vscode.commands.executeCommand(`code-for-ibmi.debug.setup.local`);
}
}
} else {
const openTut = await vscode.window.showInformationMessage(`Looks like you have the debug PTF installed. Do you want to see the Walkthrough to set it up?`, `Take me there`);
Expand All @@ -319,12 +337,12 @@ export async function startDebug(instance: Instance, options: DebugOptions) {

const port = config?.debugPort;
const updateProductionFiles = config?.debugUpdateProductionFiles;
const enableDebugTracing = config?.debugEnableDebugTracing; // TODO: configurable
const enableDebugTracing = config?.debugEnableDebugTracing;

const secure = config?.debugSecure; // TODO: make configurable
const secure = config?.debugIsSecure;

if (secure) {
process.env[`DEBUG_CA_PATH`] = certificates.getLocalCert(connection!);
process.env[`DEBUG_CA_PATH`] = certificates.getLocalCertPath(connection!);
}

const pathKey = options.library.trim() + `/` + options.object.trim();
Expand Down
10 changes: 5 additions & 5 deletions src/webviews/settings/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,6 @@ module.exports = class SettingsUI {
field.description = `Default secure port is <code>8005</code>. Tells the client which port the debug service is running on.`;
ui.addField(field);

field = new Field(`checkbox`, `debugSecure`, `Debug securely`);
field.default = (config.debugSecure ? `checked` : ``);
field.description = `Ensures that the client and debug service are connected securely.`;
ui.addField(field);

field = new Field(`checkbox`, `debugUpdateProductionFiles`, `Update production files`);
field.default = (config.debugUpdateProductionFiles ? `checked` : ``);
field.description = `Determines whether the job being debugged can update objects in production (<code>*PROD</code>) libraries.`;
Expand All @@ -222,6 +217,11 @@ module.exports = class SettingsUI {
field.default = (config.debugEnableDebugTracing ? `checked` : ``);
field.description = `Tells the debug service to send more data to the client. Only useful for debugging issues in the service. Not recommended for general debugging.`;
ui.addField(field);

field = new Field(`checkbox`, `debugIsSecure`, `Debug securely`);
field.default = (config.debugIsSecure ? `checked` : ``);
field.description = `Tells the debug service to authenticate by server and client certificates. Ensure that the client certificate is imported when enabled.`;
ui.addField(field);
}

ui.addField(new Field(`hr`));
Expand Down

0 comments on commit 539c955

Please sign in to comment.