From b670775b118a60e51dadf79fa1eb46f1f124478b Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Fri, 23 Aug 2024 21:37:22 +0200 Subject: [PATCH] Added additional checks for debug config/certificate Signed-off-by: Seb Julliand --- src/api/debug/certificates.ts | 6 ++- src/api/debug/config.ts | 10 +++- src/api/debug/index.ts | 5 +- src/locale/ids/en.json | 10 ++-- src/views/debugView.ts | 87 ++++++++++++++++++++++------------- 5 files changed, 77 insertions(+), 41 deletions(-) diff --git a/src/api/debug/certificates.ts b/src/api/debug/certificates.ts index c3188347b..e8fa7eae6 100644 --- a/src/api/debug/certificates.ts +++ b/src/api/debug/certificates.ts @@ -191,7 +191,7 @@ export async function setup(connection: IBMi, imported?: ImportedCertificate) { debugConfig.set("JAVA_HOME", javaHome); debugConfig.set("DEBUG_SERVICE_KEYSTORE_FILE", certificatePath); debugConfig.set("DEBUG_SERVICE_KEYSTORE_PASSWORD", encryptResult.stdout); - debugConfig.set("CODE4IDEBUG", `$([ -f $DBGSRV_WRK_DIR/${ENCRYPTION_KEY} ] && cp $DBGSRV_WRK_DIR/${ENCRYPTION_KEY} $DBGSRV_WRK_DIR/key.properties)`); + debugConfig.setCode4iDebug(`$([ -f $DBGSRV_WRK_DIR/${ENCRYPTION_KEY} ] && cp $DBGSRV_WRK_DIR/${ENCRYPTION_KEY} $DBGSRV_WRK_DIR/key.properties)`); debugConfig.save(); } else { @@ -210,6 +210,10 @@ export async function setup(connection: IBMi, imported?: ImportedCertificate) { }); } +export async function debugKeyFileExists(connection: IBMi, debugConfig: DebugConfiguration) { + return await connection.content.testStreamFile(`${debugConfig.getRemoteServiceWorkDir()}/.code4i.debug`, "f"); +} + export async function remoteCertificatesExists(debugConfig?: DebugConfiguration) { const content = instance.getContent(); if (content) { diff --git a/src/api/debug/config.ts b/src/api/debug/config.ts index cad962b1f..324402d40 100644 --- a/src/api/debug/config.ts +++ b/src/api/debug/config.ts @@ -91,6 +91,14 @@ export class DebugConfiguration { getRemoteServiceWorkDir() { return this.getOrDefault("DBGSRV_WRK_DIR", "/QIBM/UserData/IBMiDebugService"); } + + getCode4iDebug() { + return this.get("CODE4IDEBUG"); + } + + setCode4iDebug(value: string) { + return this.set("CODE4IDEBUG", value); + } } interface DebugServiceDetails { @@ -145,7 +153,7 @@ export async function getDebugServiceDetails(): Promise { console.log(e); } } - else{ + else { details = { version: `1.0.0`, java: `8`, diff --git a/src/api/debug/index.ts b/src/api/debug/index.ts index 3e78e2885..2f242f52f 100644 --- a/src/api/debug/index.ts +++ b/src/api/debug/index.ts @@ -283,8 +283,9 @@ export async function initialize(context: ExtensionContext) { const ptfInstalled = server.debugPTFInstalled(); if (ptfInstalled) { - const remoteCertsExists = await certificates.remoteCertificatesExists(); - if (remoteCertsExists) { + const debugConfig = await new DebugConfiguration().load() + const remoteCertsExists = await certificates.remoteCertificatesExists(debugConfig); + if (remoteCertsExists && await certificates.debugKeyFileExists(connection, debugConfig) && debugConfig.getCode4iDebug()) { await certificates.downloadClientCert(connection); vscode.window.showInformationMessage(`Debug Service Certificate already exist on the server. The client certificate has been downloaded to enable debugging.`); } diff --git a/src/locale/ids/en.json b/src/locale/ids/en.json index b0196009b..d73988885 100644 --- a/src/locale/ids/en.json +++ b/src/locale/ids/en.json @@ -360,7 +360,7 @@ "objectBrowser.uploadAndReplaceMemberAsFile.infoMessage": "Member was uploaded.", "offline": "Offline", "online": "Online", - "open":"Open", + "open": "Open", "open.service.configuration": "Open configuration", "overview": "Overview", "overwrite": "Overwrite", @@ -394,8 +394,8 @@ "sandbox.noconnection.modal.title": "Oh no! The sandbox is down.", "sandbox.noPassword": "Connection to {0} ended as no password was provided.", "save": "Save", - "searchView.find.message":"{0} file(s) named '{1}'", - "searchView.search.message":"{0} file(s) contain(s) '{1}'", + "searchView.find.message": "{0} file(s) named '{1}'", + "searchView.search.message": "{0} file(s) contain(s) '{1}'", "service.certificate.exists": "Remote service certificate exists", "shortcut": "shortcut", "size": "Size", @@ -422,5 +422,7 @@ "type": "Type", "USER_DIRECTORY": "User directory", "username": "Username", - "Yes": "Yes" + "Yes": "Yes", + "debug.service.config.incomplete": "Incomplete configuration", + "debug.service.config.incomplete.detail": "Certificate needs to be regenerated" } \ No newline at end of file diff --git a/src/views/debugView.ts b/src/views/debugView.ts index 6dcc9803a..0a984ff05 100644 --- a/src/views/debugView.ts +++ b/src/views/debugView.ts @@ -1,6 +1,6 @@ import vscode from "vscode"; import { Tools } from "../api/Tools"; -import { checkClientCertificate, remoteCertificatesExists } from "../api/debug/certificates"; +import { checkClientCertificate, debugKeyFileExists, remoteCertificatesExists } from "../api/debug/certificates"; import { DebugConfiguration, getDebugServiceDetails } from "../api/debug/config"; import { DebugJob, getDebugServerJob, getDebugServiceJob, isDebugEngineRunning, readActiveJob, readJVMInfo, startServer, startService, stopServer, stopService } from "../api/debug/server"; import { instance } from "../instantiate"; @@ -14,7 +14,7 @@ type Certificates = { localCertificateIssue?: string } -type CertificateIssue = { +type DebugServiceIssue = { label: string detail?: string context: string @@ -74,6 +74,8 @@ class DebugBrowser implements vscode.TreeDataProvider { const connection = instance.getConnection(); if (connection) { const debugConfig = await new DebugConfiguration().load(); + const keyFileExists = await debugKeyFileExists(connection, debugConfig); + const certificates: Certificates = { remoteCertificate: await remoteCertificatesExists(debugConfig), remoteCertificatePath: debugConfig.getRemoteServiceCertificatePath() @@ -89,22 +91,25 @@ class DebugBrowser implements vscode.TreeDataProvider { } return Promise.all([ - getDebugServerJob().then(job => + getDebugServerJob().then(debugJob => new DebugJobItem("server", t("debug.server"), - startServer, - stopServer, - job - ) + { + startFunction: startServer, + stopFunction: stopServer, + debugJob + }) ), - getDebugServiceJob().then(job => + getDebugServiceJob().then(debugJob => new DebugJobItem("service", - t("debug.service"), - () => startService(connection), - () => stopService(connection), - job, - certificates - ) + t("debug.service"), { + startFunction: () => startService(connection), + stopFunction: () => stopService(connection), + debugJob, + debugConfig, + certificates, + keyFileExists + }) ) ]); } @@ -115,15 +120,15 @@ class DebugBrowser implements vscode.TreeDataProvider { async resolveTreeItem(item: vscode.TreeItem, element: BrowserItem, token: vscode.CancellationToken) { const connection = instance.getConnection(); - if (connection && element.tooltip === undefined && element instanceof DebugJobItem && element.debugJob) { - element.tooltip = new vscode.MarkdownString(`${t(`listening.on.port${element.debugJob.ports.length === 1 ? '' : 's'}`)} ${element.debugJob.ports.join(", ")}\n\n`); - const activeJob = await readActiveJob(connection, element.debugJob); + if (connection && element.tooltip === undefined && element instanceof DebugJobItem && element.parameters.debugJob) { + element.tooltip = new vscode.MarkdownString(`${t(`listening.on.port${element.parameters.debugJob.ports.length === 1 ? '' : 's'}`)} ${element.parameters.debugJob.ports.join(", ")}\n\n`); + const activeJob = await readActiveJob(connection, element.parameters.debugJob); if (activeJob) { const jobToMarkDown = (job: Tools.DB2Row | string) => typeof job === "string" ? job : Object.entries(job).filter(([key, value]) => value !== null).map(([key, value]) => `- ${t(key)}: ${value}`).join("\n"); element.tooltip.appendMarkdown(jobToMarkDown(activeJob)); if (element.type === "service") { element.tooltip.appendMarkdown("\n\n"); - const jvmJob = await readJVMInfo(connection, element.debugJob); + const jvmJob = await readJVMInfo(connection, element.parameters.debugJob); if (jvmJob) { element.tooltip.appendMarkdown(jobToMarkDown(jvmJob)); } @@ -142,24 +147,40 @@ class DebugItem extends BrowserItem { } class DebugJobItem extends DebugItem { - private problem: undefined | CertificateIssue; - - constructor(readonly type: "server" | "service", label: string, readonly startFunction: () => Promise, readonly stopFunction: () => Promise, readonly debugJob?: DebugJob, certificates?: Certificates) { - let problem: undefined | CertificateIssue - const cantRun = certificates && !certificates.remoteCertificate; - const running = !cantRun && debugJob !== undefined; - if (certificates) { - if (!certificates.remoteCertificate) { + private problem: undefined | DebugServiceIssue; + + constructor(readonly type: "server" | "service", label: string, readonly parameters: { + startFunction: () => Promise, + stopFunction: () => Promise, + debugJob?: DebugJob, + certificates?: Certificates, + debugConfig?: DebugConfiguration, + keyFileExists?: boolean + }) { + let problem: undefined | DebugServiceIssue + let cantRun = false; + const running = !cantRun && parameters.debugJob !== undefined; + if (parameters.certificates && parameters.debugConfig) { + if (parameters.debugConfig && (!parameters.debugConfig.getCode4iDebug() || !parameters.keyFileExists)) { + cantRun = true; + problem = { + context: "noremote", + label: t('debug.service.config.incomplete'), + detail: t('debug.service.config.incomplete.detail', "debug_service.pfx", parameters.certificates.remoteCertificatePath) + } + } + else if (!parameters.certificates.remoteCertificate) { + cantRun = true; problem = { context: "noremote", label: t('remote.certificate.not.found'), - detail: t('remote.certificate.not.found.detail', "debug_service.pfx", certificates.remoteCertificatePath) + detail: t('remote.certificate.not.found.detail', "debug_service.pfx", parameters.certificates.remoteCertificatePath) } } - else if (certificates.localCertificateIssue) { + else if (parameters.certificates.localCertificateIssue) { problem = { context: "localissue", - label: certificates.localCertificateIssue + label: parameters.certificates.localCertificateIssue }; } } @@ -173,7 +194,7 @@ class DebugJobItem extends DebugItem { this.problem = problem; if (running) { - this.description = debugJob.name; + this.description = this.parameters.debugJob!.name; } else { this.description = t("offline"); @@ -188,16 +209,16 @@ class DebugJobItem extends DebugItem { } async start() { - return vscode.window.withProgress({ title: t(`start.debug.${this.type}.task`), location: vscode.ProgressLocation.Window }, this.startFunction); + return vscode.window.withProgress({ title: t(`start.debug.${this.type}.task`), location: vscode.ProgressLocation.Window }, this.parameters.startFunction); } async stop() { - return vscode.window.withProgress({ title: t(`stop.debug.${this.type}.task`), location: vscode.ProgressLocation.Window }, this.stopFunction); + return vscode.window.withProgress({ title: t(`stop.debug.${this.type}.task`), location: vscode.ProgressLocation.Window }, this.parameters.stopFunction); } } class CertificateIssueItem extends DebugItem { - constructor(issue: CertificateIssue) { + constructor(issue: DebugServiceIssue) { super(issue.label) this.description = issue.detail; this.tooltip = issue.detail || '';