From 4481b2ffce1b42828dd331160e8bb4bd47124d6e Mon Sep 17 00:00:00 2001 From: worksofliam Date: Fri, 29 Nov 2024 18:48:11 -0500 Subject: [PATCH 1/9] Fix for getAttributes for files with spaces Signed-off-by: worksofliam --- src/api/IBMiContent.ts | 6 +++--- src/testing/encoding.ts | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index 6c6871308..4efed6a1d 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -957,15 +957,15 @@ export default class IBMiContent { target = localPath; } - target = IBMi.escapeForShell(target); - let result: CommandResult; if (assumeMember) { + target = IBMi.escapeForShell(target); result = await this.ibmi.sendQsh({ command: `${this.ibmi.remoteFeatures.attr} -p ${target} ${operands.join(" ")}`}); } else { + target = Tools.escapePath(target, true); // Take {DOES_THIS_WORK: `YESITDOES`} away, and all of a sudden names with # aren't found. - result = await this.ibmi.sendCommand({ command: `${this.ibmi.remoteFeatures.attr} -p ${target} ${operands.join(" ")}`, env: {DOES_THIS_WORK: `YESITDOES`}}); + result = await this.ibmi.sendCommand({ command: `${this.ibmi.remoteFeatures.attr} -p "${target}" ${operands.join(" ")}`, env: {DOES_THIS_WORK: `YESITDOES`}}); } if (result.code === 0) { diff --git a/src/testing/encoding.ts b/src/testing/encoding.ts index e89fe1327..73f4047c6 100644 --- a/src/testing/encoding.ts +++ b/src/testing/encoding.ts @@ -91,6 +91,26 @@ export const EncodingSuite: TestSuite = { assert.ok(result?.length); } }, + { + name: `Files and directories with spaces`, test: async () => { + const connection = instance.getConnection()!; + + await connection.withTempDirectory(async tempDir => { + const dirWithSpace = path.posix.join(tempDir, `hello world`); + const fileName = `hello world.txt`; + const nameWithSpace = path.posix.join(dirWithSpace, fileName); + + await connection.sendCommand({command: `mkdir -p "${dirWithSpace}"`}); + await connection.content.createStreamFile(nameWithSpace); + + const resolved = await connection.content.streamfileResolve([fileName], [tempDir, dirWithSpace]); + assert.strictEqual(resolved, nameWithSpace); + + const attributes = await connection.content.getAttributes(resolved, `CCSID`); + assert.ok(attributes); + }); + } + }, { name: `Run variants through shells`, test: async () => { const connection = instance.getConnection(); From b77f7591970bef3c0fef661d68b7f62cb90eb7b9 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Fri, 29 Nov 2024 18:52:50 -0500 Subject: [PATCH 2/9] Additional logic in test Signed-off-by: worksofliam --- src/testing/encoding.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/testing/encoding.ts b/src/testing/encoding.ts index 73f4047c6..bd486ad35 100644 --- a/src/testing/encoding.ts +++ b/src/testing/encoding.ts @@ -96,18 +96,36 @@ export const EncodingSuite: TestSuite = { const connection = instance.getConnection()!; await connection.withTempDirectory(async tempDir => { - const dirWithSpace = path.posix.join(tempDir, `hello world`); + const dirName = `hello world`; + const dirWithSpace = path.posix.join(tempDir, dirName); const fileName = `hello world.txt`; const nameWithSpace = path.posix.join(dirWithSpace, fileName); await connection.sendCommand({command: `mkdir -p "${dirWithSpace}"`}); await connection.content.createStreamFile(nameWithSpace); + // Resolve and get attributes const resolved = await connection.content.streamfileResolve([fileName], [tempDir, dirWithSpace]); assert.strictEqual(resolved, nameWithSpace); const attributes = await connection.content.getAttributes(resolved, `CCSID`); assert.ok(attributes); + + // Write and read the files + const uri = Uri.from({scheme: `streamfile`, path: nameWithSpace}); + await workspace.fs.writeFile(uri, Buffer.from(`Hello world`, `utf8`)); + + const streamfileContents = await workspace.fs.readFile(uri); + assert.ok(streamfileContents.toString().includes(`Hello world`)); + + // List files + const files = await connection.content.getFileList(tempDir); + assert.strictEqual(files.length, 1); + assert.ok(files.some(f => f.name === dirName && f.path === dirWithSpace)); + + const files2 = await connection.content.getFileList(dirWithSpace); + assert.strictEqual(files2.length, 1); + assert.ok(files2.some(f => f.name === fileName && f.path === nameWithSpace)); }); } }, From f50171db6aa87cb99ba60e3b58f7c8d41f3c8a8c Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Mon, 2 Dec 2024 10:50:14 +0100 Subject: [PATCH 3/9] Added parameter to translate home dir from CustomUI filepicker Signed-off-by: Seb Julliand --- src/api/CustomUI.ts | 35 ++++++++++++++++++++++------------ src/webviews/login/index.ts | 2 +- src/webviews/settings/index.ts | 2 +- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/api/CustomUI.ts b/src/api/CustomUI.ts index 7fe892f7a..604417c11 100644 --- a/src/api/CustomUI.ts +++ b/src/api/CustomUI.ts @@ -1,4 +1,5 @@ /* eslint-disable indent */ +import os from "os"; import vscode from 'vscode'; //Webpack is returning this as a string @@ -37,7 +38,7 @@ export interface ComplexTab { } interface WebviewMessageRequest { - type: "submit"|"file"; + type: "submit" | "file"; data?: any; } @@ -72,8 +73,10 @@ export class Section { return this; } - addFile(id: string, label: string, description?: string) { - this.addField(new Field('file', id, label, description)); + addFile(id: string, label: string, description?: string, homeAsVar?: boolean) { + const fileInput = new Field('file', id, label, description); + fileInput.homeAsVar = homeAsVar; + this.addField(fileInput); return this; } @@ -194,11 +197,17 @@ export class CustomUI extends Section { canSelectFiles: true, canSelectMany: false, canSelectFolders: false, - }).then(result => { - if (result) { - panel.webview.postMessage({ type: `update`, field: resultField, value: result[0].fsPath }); - } - }); + }) + .then(selected => selected?.at(0)?.fsPath) + .then(path => { + if (path) { + const filePath = message.data.translateHomeVar && path.startsWith(os.homedir()) ? + path.replace(os.homedir(), '~') : + path; + console.log(filePath); + panel.webview.postMessage({ type: `update`, field: resultField, value: filePath }); + } + }); } break; } @@ -379,11 +388,11 @@ export class CustomUI extends Section { vscode.postMessage({ type: 'submit', data: {treeId, value} }); } - const doFileRequest = (event, fieldId) => { + const doFileRequest = (event, fieldId, translateHomeVar) => { if (event) event.preventDefault(); - vscode.postMessage({ type: 'file', data: {field: fieldId} }); + vscode.postMessage({ type: 'file', data: {field: fieldId, translateHomeVar} }); } // Setup the input fields for validation @@ -438,7 +447,7 @@ export class CustomUI extends Section { for (const field of filefields) { let fileButton = document.getElementById(field + '-file'); if (fileButton) { - fileButton.onclick = (event) => doFileRequest(event, field); + fileButton.onclick = (event) => doFileRequest(event, field, fileButton.dataset.homevar === "true"); } } @@ -506,6 +515,8 @@ export class Field { public maxlength?: number; public regexTest?: string; + public homeAsVar?: boolean; + constructor(readonly type: FieldType, readonly id: string, readonly label: string, readonly description?: string) { } @@ -586,7 +597,7 @@ export class Field { ${this.renderDescription()}

- Select File + Select File `; case `password`: diff --git a/src/webviews/login/index.ts b/src/webviews/login/index.ts index 2c6943541..a592880b4 100644 --- a/src/webviews/login/index.ts +++ b/src/webviews/login/index.ts @@ -32,7 +32,7 @@ export class Login { .addParagraph(l10n.t(`Only provide either the password or a private key - not both.`)) .addPassword(`password`, l10n.t(`Password`)) .addCheckbox(`savePassword`, l10n.t(`Save Password`)) - .addFile(`privateKeyPath`, l10n.t(`Private Key`), l10n.t(`OpenSSH, RFC4716, or PPK formats are supported.`)); + .addFile(`privateKeyPath`, l10n.t(`Private Key`), l10n.t(`OpenSSH, RFC4716, or PPK formats are supported.`), true); const tempTab = new Section() .addInput(`tempLibrary`, `Temporary library`, `Temporary library. Cannot be QTEMP.`, { default: `ILEDITOR`, minlength: 1, maxlength: 10 }) diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 9f3e2083e..4b171d82f 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -359,7 +359,7 @@ export class SettingsUI { .addInput(`username`, vscode.l10n.t(`Username`), undefined, { default: stored.username, minlength: 1 }) .addParagraph(vscode.l10n.t(`Only provide either the password or a private key - not both.`)) .addPassword(`password`, `${vscode.l10n.t(`Password`)}${storedPassword ? ` (${vscode.l10n.t(`stored`)})` : ``}`, vscode.l10n.t("Only provide a password if you want to update an existing one or set a new one.")) - .addFile(`privateKeyPath`, `${vscode.l10n.t(`Private Key`)}${stored.privateKeyPath ? ` (${vscode.l10n.t(`Private Key`)}: ${stored.privateKeyPath})` : ``}`, vscode.l10n.t("Only provide a private key if you want to update from the existing one or set one.") + '
' + vscode.l10n.t("OpenSSH, RFC4716 and PPK formats are supported.")) + .addFile(`privateKeyPath`, `${vscode.l10n.t(`Private Key`)}${stored.privateKeyPath ? ` (${vscode.l10n.t(`Private Key`)}: ${stored.privateKeyPath})` : ``}`, vscode.l10n.t("Only provide a private key if you want to update from the existing one or set one.") + '
' + vscode.l10n.t("OpenSSH, RFC4716 and PPK formats are supported."), true) .addButtons( { id: `submitButton`, label: vscode.l10n.t(`Save`), requiresValidation: true }, { id: `removeAuth`, label: vscode.l10n.t(`Remove auth methods`) } From b325680e982f4d56c04b3310b2d1e0a846d61915 Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Mon, 2 Dec 2024 11:59:07 +0100 Subject: [PATCH 4/9] Revert "Added parameter to translate home dir from CustomUI filepicker" This reverts commit f50171db6aa87cb99ba60e3b58f7c8d41f3c8a8c. --- src/api/CustomUI.ts | 35 ++++++++++++---------------------- src/webviews/login/index.ts | 2 +- src/webviews/settings/index.ts | 2 +- 3 files changed, 14 insertions(+), 25 deletions(-) diff --git a/src/api/CustomUI.ts b/src/api/CustomUI.ts index 604417c11..7fe892f7a 100644 --- a/src/api/CustomUI.ts +++ b/src/api/CustomUI.ts @@ -1,5 +1,4 @@ /* eslint-disable indent */ -import os from "os"; import vscode from 'vscode'; //Webpack is returning this as a string @@ -38,7 +37,7 @@ export interface ComplexTab { } interface WebviewMessageRequest { - type: "submit" | "file"; + type: "submit"|"file"; data?: any; } @@ -73,10 +72,8 @@ export class Section { return this; } - addFile(id: string, label: string, description?: string, homeAsVar?: boolean) { - const fileInput = new Field('file', id, label, description); - fileInput.homeAsVar = homeAsVar; - this.addField(fileInput); + addFile(id: string, label: string, description?: string) { + this.addField(new Field('file', id, label, description)); return this; } @@ -197,17 +194,11 @@ export class CustomUI extends Section { canSelectFiles: true, canSelectMany: false, canSelectFolders: false, - }) - .then(selected => selected?.at(0)?.fsPath) - .then(path => { - if (path) { - const filePath = message.data.translateHomeVar && path.startsWith(os.homedir()) ? - path.replace(os.homedir(), '~') : - path; - console.log(filePath); - panel.webview.postMessage({ type: `update`, field: resultField, value: filePath }); - } - }); + }).then(result => { + if (result) { + panel.webview.postMessage({ type: `update`, field: resultField, value: result[0].fsPath }); + } + }); } break; } @@ -388,11 +379,11 @@ export class CustomUI extends Section { vscode.postMessage({ type: 'submit', data: {treeId, value} }); } - const doFileRequest = (event, fieldId, translateHomeVar) => { + const doFileRequest = (event, fieldId) => { if (event) event.preventDefault(); - vscode.postMessage({ type: 'file', data: {field: fieldId, translateHomeVar} }); + vscode.postMessage({ type: 'file', data: {field: fieldId} }); } // Setup the input fields for validation @@ -447,7 +438,7 @@ export class CustomUI extends Section { for (const field of filefields) { let fileButton = document.getElementById(field + '-file'); if (fileButton) { - fileButton.onclick = (event) => doFileRequest(event, field, fileButton.dataset.homevar === "true"); + fileButton.onclick = (event) => doFileRequest(event, field); } } @@ -515,8 +506,6 @@ export class Field { public maxlength?: number; public regexTest?: string; - public homeAsVar?: boolean; - constructor(readonly type: FieldType, readonly id: string, readonly label: string, readonly description?: string) { } @@ -597,7 +586,7 @@ export class Field { ${this.renderDescription()}

- Select File + Select File `; case `password`: diff --git a/src/webviews/login/index.ts b/src/webviews/login/index.ts index a592880b4..2c6943541 100644 --- a/src/webviews/login/index.ts +++ b/src/webviews/login/index.ts @@ -32,7 +32,7 @@ export class Login { .addParagraph(l10n.t(`Only provide either the password or a private key - not both.`)) .addPassword(`password`, l10n.t(`Password`)) .addCheckbox(`savePassword`, l10n.t(`Save Password`)) - .addFile(`privateKeyPath`, l10n.t(`Private Key`), l10n.t(`OpenSSH, RFC4716, or PPK formats are supported.`), true); + .addFile(`privateKeyPath`, l10n.t(`Private Key`), l10n.t(`OpenSSH, RFC4716, or PPK formats are supported.`)); const tempTab = new Section() .addInput(`tempLibrary`, `Temporary library`, `Temporary library. Cannot be QTEMP.`, { default: `ILEDITOR`, minlength: 1, maxlength: 10 }) diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 4b171d82f..9f3e2083e 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -359,7 +359,7 @@ export class SettingsUI { .addInput(`username`, vscode.l10n.t(`Username`), undefined, { default: stored.username, minlength: 1 }) .addParagraph(vscode.l10n.t(`Only provide either the password or a private key - not both.`)) .addPassword(`password`, `${vscode.l10n.t(`Password`)}${storedPassword ? ` (${vscode.l10n.t(`stored`)})` : ``}`, vscode.l10n.t("Only provide a password if you want to update an existing one or set a new one.")) - .addFile(`privateKeyPath`, `${vscode.l10n.t(`Private Key`)}${stored.privateKeyPath ? ` (${vscode.l10n.t(`Private Key`)}: ${stored.privateKeyPath})` : ``}`, vscode.l10n.t("Only provide a private key if you want to update from the existing one or set one.") + '
' + vscode.l10n.t("OpenSSH, RFC4716 and PPK formats are supported."), true) + .addFile(`privateKeyPath`, `${vscode.l10n.t(`Private Key`)}${stored.privateKeyPath ? ` (${vscode.l10n.t(`Private Key`)}: ${stored.privateKeyPath})` : ``}`, vscode.l10n.t("Only provide a private key if you want to update from the existing one or set one.") + '
' + vscode.l10n.t("OpenSSH, RFC4716 and PPK formats are supported.")) .addButtons( { id: `submitButton`, label: vscode.l10n.t(`Save`), requiresValidation: true }, { id: `removeAuth`, label: vscode.l10n.t(`Remove auth methods`) } From a9ca1ca840f45231484bab0b8e2cd14ae800fd4f Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Mon, 2 Dec 2024 12:00:34 +0100 Subject: [PATCH 5/9] Removed unused method Signed-off-by: Seb Julliand --- src/extension.ts | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index c383bb514..7f204a824 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -8,7 +8,7 @@ import { CustomUI } from "./api/CustomUI"; import { instance, loadAllofExtension } from './instantiate'; import { CompileTools } from "./api/CompileTools"; -import { ConnectionConfiguration, ConnectionManager, GlobalConfiguration, onCodeForIBMiConfigurationChange } from "./api/Configuration"; +import { ConnectionConfiguration, ConnectionManager, onCodeForIBMiConfigurationChange } from "./api/Configuration"; import IBMi from "./api/IBMi"; import { GlobalStorage } from "./api/Storage"; import { Tools } from "./api/Tools"; @@ -142,38 +142,6 @@ export async function activate(context: ExtensionContext): Promise }; } -async function fixLoginSettings() { - const connections = (GlobalConfiguration.get(`connections`) || []); - let update = false; - for (const connection of connections) { - //privateKey was used to hold privateKeyPath - if ('privateKey' in connection) { - const privateKey = connection["privateKey"] as string; - if (privateKey) { - connection.privateKeyPath = privateKey; - } - delete connection["privateKey"]; - update = true; - } - - //An empty privateKeyPath will crash the connection - if (!connection.privateKeyPath?.trim()) { - connection.privateKeyPath = undefined; - update = true; - } - - //buttons were added by the login settings page - if (`buttons` in connection) { - delete connection["buttons"]; - update = true; - } - } - - if (update) { - await GlobalConfiguration.set(`connections`, connections); - } -} - // this method is called when your extension is deactivated export async function deactivate() { await commands.executeCommand(`code-for-ibmi.disconnect`, true); From 362a2206e4b779dd96cd7f428794ea13b26074f5 Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Mon, 2 Dec 2024 12:12:50 +0100 Subject: [PATCH 6/9] Removed unused privateKey field Signed-off-by: Seb Julliand --- src/typings.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/typings.ts b/src/typings.ts index 381b4e6cb..753808116 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -83,7 +83,6 @@ export interface ConnectionData { port: number; username: string; password?: string; - privateKey?: string; privateKeyPath?: string; keepaliveInterval?: number; } From 9e6cf5d34d4eed5e815889632214fecfbea79dac Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Mon, 2 Dec 2024 12:36:31 +0100 Subject: [PATCH 7/9] Normaize/resolve private key path Signed-off-by: Seb Julliand --- src/api/IBMi.ts | 7 +++++-- src/api/Tools.ts | 34 ++++++++++++++++++++++++++++++++-- src/webviews/login/index.ts | 3 ++- src/webviews/settings/index.ts | 4 +++- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 27fdee307..2ec8228b4 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -182,7 +182,10 @@ export default class IBMi { }); const delayedOperations: Function[] = [...onConnectedOperations]; - await this.client.connect(connectionObject as node_ssh.Config); + await this.client.connect({ + ...connectionObject, + privateKeyPath: connectionObject.privateKeyPath ? Tools.resolvePath(connectionObject.privateKeyPath) : undefined + } as node_ssh.Config); cancelToken.onCancellationRequested(() => { this.end(); @@ -1504,7 +1507,7 @@ export default class IBMi { return this.componentManager.get(name, ignoreState); } - getComponentStates(){ + getComponentStates() { return this.componentManager.getState(); } diff --git a/src/api/Tools.ts b/src/api/Tools.ts index 6b68d3402..7c760ba1b 100644 --- a/src/api/Tools.ts +++ b/src/api/Tools.ts @@ -1,5 +1,6 @@ import Crypto from 'crypto'; import { readFileSync } from "fs"; +import os from "os"; import path from "path"; import vscode from "vscode"; import { IBMiMessage, IBMiMessages, QsysPath } from '../typings'; @@ -401,14 +402,14 @@ export namespace Tools { export function assumeType(str: string) { if (str.trim().length === 0) return ``; - + // The number is already generated on the server. // So, we assume that if the string starts with a 0, it is a string. if (/^0.+/.test(str) || str.length > 10) { return str } const number = Number(str); - if(isNaN(number)){ + if (isNaN(number)) { return str; } return number; @@ -463,4 +464,33 @@ export namespace Tools { } return 0; } + + /** + * Transforms a file path into an OS agnostic path. + * - Replaces full home directory path by ~ + * - Replaces all \ into / on Windows + * + * @param filePath + * @returns + */ + export function normalizePath(filePath: string) { + //Test path in lowercase since os.homedir doesn't always has the same case as filePath on Windows + if(filePath.toLowerCase().startsWith(os.homedir().toLowerCase())){ + filePath = path.join(`~`, filePath.substring(os.homedir().length)); + } + + return process.platform === "win32" ? filePath.replaceAll('\\', '/') : filePath; + } + + /** + * Transforms a normalized path into an OS specific path. + * - Replaces ~ with the current home directory + * - Changes all / to \ on Windows + * @param path + * @returns + */ + export function resolvePath(path: string) { + path = path.replace("~", os.homedir()); + return process.platform === "win32" ? path.replaceAll('/', '\\') : path; + } } \ No newline at end of file diff --git a/src/webviews/login/index.ts b/src/webviews/login/index.ts index 2c6943541..137eba7c5 100644 --- a/src/webviews/login/index.ts +++ b/src/webviews/login/index.ts @@ -2,6 +2,7 @@ import vscode, { l10n, ThemeIcon } from "vscode"; import { ConnectionConfiguration, ConnectionManager } from "../../api/Configuration"; import { CustomUI, Section } from "../../api/CustomUI"; import IBMi from "../../api/IBMi"; +import { Tools } from "../../api/Tools"; import { disconnect, instance } from "../../instantiate"; import { ConnectionData } from '../../typings'; @@ -54,7 +55,7 @@ export class Login { page.panel.dispose(); data.port = Number(data.port); - data.privateKeyPath = data.privateKeyPath?.trim() ? data.privateKeyPath : undefined; + data.privateKeyPath = data.privateKeyPath?.trim() ? Tools.normalizePath(data.privateKeyPath) : undefined; if (data.name) { const existingConnection = ConnectionManager.getByName(data.name); diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 9f3e2083e..0e322a8d7 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -359,7 +359,7 @@ export class SettingsUI { .addInput(`username`, vscode.l10n.t(`Username`), undefined, { default: stored.username, minlength: 1 }) .addParagraph(vscode.l10n.t(`Only provide either the password or a private key - not both.`)) .addPassword(`password`, `${vscode.l10n.t(`Password`)}${storedPassword ? ` (${vscode.l10n.t(`stored`)})` : ``}`, vscode.l10n.t("Only provide a password if you want to update an existing one or set a new one.")) - .addFile(`privateKeyPath`, `${vscode.l10n.t(`Private Key`)}${stored.privateKeyPath ? ` (${vscode.l10n.t(`Private Key`)}: ${stored.privateKeyPath})` : ``}`, vscode.l10n.t("Only provide a private key if you want to update from the existing one or set one.") + '
' + vscode.l10n.t("OpenSSH, RFC4716 and PPK formats are supported.")) + .addFile(`privateKeyPath`, `${vscode.l10n.t(`Private Key`)}${stored.privateKeyPath ? ` (${vscode.l10n.t(`Private Key`)}: ${Tools.resolvePath(stored.privateKeyPath)})` : ``}`, vscode.l10n.t("Only provide a private key if you want to update from the existing one or set one.") + '
' + vscode.l10n.t("OpenSSH, RFC4716 and PPK formats are supported.")) .addButtons( { id: `submitButton`, label: vscode.l10n.t(`Save`), requiresValidation: true }, { id: `removeAuth`, label: vscode.l10n.t(`Remove auth methods`) } @@ -393,6 +393,8 @@ export class SettingsUI { // If no password was entered, but a keypath exists // then remove the password from the data and // use the keypath instead + data.privateKeyPath = Tools.normalizePath(data.privateKeyPath); + console.log(data.privateKeyPath) await ConnectionManager.deleteStoredPassword(context, name); vscode.window.showInformationMessage(vscode.l10n.t(`Private key updated and will be used for "{0}".`, name)); } From 1490cab200c152153484f96b5b5687555dfb2838 Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Mon, 2 Dec 2024 13:38:15 +0100 Subject: [PATCH 8/9] Display a warning when the private key doesn't exixt locally Signed-off-by: Seb Julliand --- src/webviews/settings/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 0e322a8d7..7ec2cdb65 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -1,3 +1,4 @@ +import { existsSync } from "fs"; import vscode from "vscode"; import { ConnectionConfiguration, ConnectionManager, GlobalConfiguration } from "../../api/Configuration"; import { ComplexTab, CustomUI, Section } from "../../api/CustomUI"; @@ -352,14 +353,15 @@ export class SettingsUI { if (connection) { const storedPassword = await ConnectionManager.getStoredPassword(context, name); let { data: stored, index } = connection; - + const privateKeyPath = stored.privateKeyPath ? Tools.resolvePath(stored.privateKeyPath) : undefined; + const privateKeyWarning = !privateKeyPath || existsSync(privateKeyPath) ? "" : "⚠️ This private key doesn't exist on this system! ⚠️

"; const ui = new CustomUI() .addInput(`host`, vscode.l10n.t(`Host or IP Address`), undefined, { default: stored.host, minlength: 1 }) .addInput(`port`, vscode.l10n.t(`Port (SSH)`), undefined, { default: String(stored.port), minlength: 1, maxlength: 5, regexTest: `^\\d+$` }) .addInput(`username`, vscode.l10n.t(`Username`), undefined, { default: stored.username, minlength: 1 }) .addParagraph(vscode.l10n.t(`Only provide either the password or a private key - not both.`)) .addPassword(`password`, `${vscode.l10n.t(`Password`)}${storedPassword ? ` (${vscode.l10n.t(`stored`)})` : ``}`, vscode.l10n.t("Only provide a password if you want to update an existing one or set a new one.")) - .addFile(`privateKeyPath`, `${vscode.l10n.t(`Private Key`)}${stored.privateKeyPath ? ` (${vscode.l10n.t(`Private Key`)}: ${Tools.resolvePath(stored.privateKeyPath)})` : ``}`, vscode.l10n.t("Only provide a private key if you want to update from the existing one or set one.") + '
' + vscode.l10n.t("OpenSSH, RFC4716 and PPK formats are supported.")) + .addFile(`privateKeyPath`, `${vscode.l10n.t(`Private Key`)}${privateKeyPath ? ` (${vscode.l10n.t(`Private Key`)}: ${privateKeyPath})` : ``}`, privateKeyWarning + vscode.l10n.t("Only provide a private key if you want to update from the existing one or set one.") + '
' + vscode.l10n.t("OpenSSH, RFC4716 and PPK formats are supported.")) .addButtons( { id: `submitButton`, label: vscode.l10n.t(`Save`), requiresValidation: true }, { id: `removeAuth`, label: vscode.l10n.t(`Remove auth methods`) } From 22ba1f46dbde491d21195aa6ac8f440223dacca8 Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Mon, 2 Dec 2024 16:11:24 +0100 Subject: [PATCH 9/9] Removed dev log Signed-off-by: Seb Julliand --- src/webviews/settings/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 7ec2cdb65..124753276 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -396,7 +396,6 @@ export class SettingsUI { // then remove the password from the data and // use the keypath instead data.privateKeyPath = Tools.normalizePath(data.privateKeyPath); - console.log(data.privateKeyPath) await ConnectionManager.deleteStoredPassword(context, name); vscode.window.showInformationMessage(vscode.l10n.t(`Private key updated and will be used for "{0}".`, name)); }