Skip to content

Commit

Permalink
Merge pull request #2393 from codefori/feature/privateKeyHome
Browse files Browse the repository at this point in the history
Make private key path OS indendant
  • Loading branch information
sebjulliand authored Dec 2, 2024
2 parents 3e93d92 + 22ba1f4 commit c3fe88b
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 41 deletions.
7 changes: 5 additions & 2 deletions src/api/IBMi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -1504,7 +1507,7 @@ export default class IBMi {
return this.componentManager.get<T>(name, ignoreState);
}

getComponentStates(){
getComponentStates() {
return this.componentManager.getState();
}

Expand Down
34 changes: 32 additions & 2 deletions src/api/Tools.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
34 changes: 1 addition & 33 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -142,38 +142,6 @@ export async function activate(context: ExtensionContext): Promise<CodeForIBMi>
};
}

async function fixLoginSettings() {
const connections = (GlobalConfiguration.get<ConnectionData[]>(`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);
Expand Down
1 change: 0 additions & 1 deletion src/typings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ export interface ConnectionData {
port: number;
username: string;
password?: string;
privateKey?: string;
privateKeyPath?: string;
keepaliveInterval?: number;
}
Expand Down
3 changes: 2 additions & 1 deletion src/webviews/login/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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);

Expand Down
7 changes: 5 additions & 2 deletions src/webviews/settings/index.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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) ? "" : "<b>⚠️ This private key doesn't exist on this system! ⚠️</b></br></br>";
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`)}: ${stored.privateKeyPath})` : ``}`, vscode.l10n.t("Only provide a private key if you want to update from the existing one or set one.") + '<br />' + 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.") + '<br />' + 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`) }
Expand Down Expand Up @@ -393,6 +395,7 @@ 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);
await ConnectionManager.deleteStoredPassword(context, name);
vscode.window.showInformationMessage(vscode.l10n.t(`Private key updated and will be used for "{0}".`, name));
}
Expand Down

0 comments on commit c3fe88b

Please sign in to comment.