From bf0ace5cc4950c5fb6a8af153f36dac7dc788d42 Mon Sep 17 00:00:00 2001 From: Levi Yan Date: Mon, 21 Oct 2024 11:39:07 +0800 Subject: [PATCH] refactro: firstconnect with key instead of password --- src/remote-container.ts | 167 ++++++++++++++++++++++++++++------------ 1 file changed, 116 insertions(+), 51 deletions(-) diff --git a/src/remote-container.ts b/src/remote-container.ts index bcaafa6..394bc0f 100644 --- a/src/remote-container.ts +++ b/src/remote-container.ts @@ -2,19 +2,19 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; import * as vscode from 'vscode'; +import * as rd from 'readline' const { NodeSSH } = require('node-ssh') + import * as utils from './utils'; export default class RemoteContainer { - async firstConnect(host: string, username: string, password: string, port: number): Promise { - return new Promise(async (resolve, reject) => { - // connect the host and add the public key to the remote authorized_keys - const defaultPublicKeyPath = path.join(os.homedir(), '.ssh', 'id_rsa.pub'); - // TODO: if there is no public key, generate one - const publicKey = fs.readFileSync(defaultPublicKeyPath, 'utf8'); + async firstConnect(host: string, username: string, port: number): Promise; // connect with key + // deprecated + async firstConnect(host: string, username: string, port: number, password: string): Promise; - // first connect to the remote host using password + async firstConnect(host: string, username: string, port: number, password?: string): Promise { + return new Promise(async (resolve, reject) => { const ssh = new NodeSSH(); vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, @@ -22,56 +22,121 @@ export default class RemoteContainer { cancellable: false }, async (progress) => { try { - await ssh.connect({ - host: host, - username: username, - password: password, - port: port - }); - progress.report({ message: "连接成功,开始安装" }); - // install vscode-server and devstar extension - const vscodeCommitId = await utils.getVsCodeCommitId(); - const vscodeServerUrl = `https://vscode.download.prss.microsoft.com/dbazure/download/stable/${vscodeCommitId}/vscode-server-linux-x64.tar.gz` - const installVscodeServerScript = ` - mkdir -p ~/.vscode-server/bin/${vscodeCommitId} && \\ - if [ "$(ls -A ~/.vscode-server/bin/${vscodeCommitId})" ]; then - ~/.vscode-server/bin/${vscodeCommitId}/bin/code-server --install-extension mengning.devstar - else - wget ${vscodeServerUrl} -O vscode-server-linux-x64.tar.gz && \\ - mv vscode-server-linux-x64.tar.gz ~/.vscode-server/bin/${vscodeCommitId} && \\ - cd ~/.vscode-server/bin/${vscodeCommitId} && \\ - tar -xvzf vscode-server-linux-x64.tar.gz --strip-components 1 && \\ - rm vscode-server-linux-x64.tar.gz && \\ - ~/.vscode-server/bin/${vscodeCommitId}/bin/code-server --install-extension mengning.devstar - fi - `; - await ssh.execCommand(installVscodeServerScript); - console.log("vscode-server and extension installed"); - vscode.window.showInformationMessage('安装完成!'); + if (password === undefined) { + // connect with key + await ssh.connect({ + host: host, + username: username, + port: port, + privateKey: utils.getDefaultPrivateKey() + }); + progress.report({ message: "连接成功,开始安装" }); - // add the public key to the remote authorized_keys - await ssh.execCommand(`mkdir -p ~/.ssh && echo '${publicKey}' >> ~/.ssh/authorized_keys`); - console.log('Public key added to remote authorized_keys'); + // install vscode-server and devstar extension + const vscodeCommitId = await utils.getVsCodeCommitId(); + const vscodeServerUrl = `https://vscode.download.prss.microsoft.com/dbazure/download/stable/${vscodeCommitId}/vscode-server-linux-x64.tar.gz` + const installVscodeServerScript = ` + mkdir -p ~/.vscode-server/bin/${vscodeCommitId} && \\ + if [ "$(ls -A ~/.vscode-server/bin/${vscodeCommitId})" ]; then + ~/.vscode-server/bin/${vscodeCommitId}/bin/code-server --install-extension mengning.devstar + else + wget ${vscodeServerUrl} -O vscode-server-linux-x64.tar.gz && \\ + mv vscode-server-linux-x64.tar.gz ~/.vscode-server/bin/${vscodeCommitId} && \\ + cd ~/.vscode-server/bin/${vscodeCommitId} && \\ + tar -xvzf vscode-server-linux-x64.tar.gz --strip-components 1 && \\ + rm vscode-server-linux-x64.tar.gz && \\ + ~/.vscode-server/bin/${vscodeCommitId}/bin/code-server --install-extension mengning.devstar + fi + `; + await ssh.execCommand(installVscodeServerScript); + console.log("vscode-server and extension installed"); + vscode.window.showInformationMessage('安装完成!'); - await ssh.dispose(); + await ssh.dispose(); + } else { + // connect with password (deprecate in future) + await ssh.connect({ + host: host, + username: username, + password: password, + port: port + }); + progress.report({ message: "连接成功,开始安装" }); + + // install vscode-server and devstar extension + const vscodeCommitId = await utils.getVsCodeCommitId(); + const vscodeServerUrl = `https://vscode.download.prss.microsoft.com/dbazure/download/stable/${vscodeCommitId}/vscode-server-linux-x64.tar.gz` + const installVscodeServerScript = ` + mkdir -p ~/.vscode-server/bin/${vscodeCommitId} && \\ + if [ "$(ls -A ~/.vscode-server/bin/${vscodeCommitId})" ]; then + ~/.vscode-server/bin/${vscodeCommitId}/bin/code-server --install-extension mengning.devstar + else + wget ${vscodeServerUrl} -O vscode-server-linux-x64.tar.gz && \\ + mv vscode-server-linux-x64.tar.gz ~/.vscode-server/bin/${vscodeCommitId} && \\ + cd ~/.vscode-server/bin/${vscodeCommitId} && \\ + tar -xvzf vscode-server-linux-x64.tar.gz --strip-components 1 && \\ + rm vscode-server-linux-x64.tar.gz && \\ + ~/.vscode-server/bin/${vscodeCommitId}/bin/code-server --install-extension mengning.devstar + fi + `; + await ssh.execCommand(installVscodeServerScript); + console.log("vscode-server and extension installed"); + vscode.window.showInformationMessage('安装完成!'); + + // add the public key to the remote authorized_keys + if (!utils.existDefaultPublicKey() || !utils.existDefaultPrivateKey()) { + // if there is no public key, generate one + utils.createSSHKey() + } + + const publicKey = utils.getDefaultPublicKey(); + await ssh.execCommand(`mkdir -p ~/.ssh && echo '${publicKey}' >> ~/.ssh/authorized_keys`); + console.log('Public key added to remote authorized_keys'); + + await ssh.dispose(); + } - // only connect successfully then save the host info - // TODO: request change password - // TODO: use remote.SSH.configFile - const sshConfigPath = path.join(os.homedir(), '.ssh', 'config'); - // append the host to the local ssh config file - const sshConfigContent = - `\nHost ${host}\n HostName ${host}\n Port ${port}\n User ${username}\n PreferredAuthentications publickey\n IdentityFile ~/.ssh/id_rsa\n `; - // append the host to the local ssh config file - fs.writeFileSync(sshConfigPath, sshConfigContent, { encoding: 'utf8', flag: 'a' }); - console.log('Host registered in local ssh config'); - resolve("success"); } catch (error) { - console.error('Error adding public key: ', error); + console.error('Failed to install vscode-server and extension: ', error); await ssh.dispose(); - reject("failed"); - }}); + reject(error); + } + + // only connect successfully then save the host info + const sshConfigPath = path.join(os.homedir(), '.ssh', 'config'); + // check if the host and related info exist in local ssh config file before saving + var canAppendSSHConfig = true + if (fs.existsSync(sshConfigPath)) { + var hasHost = false; + var hasPort = false; + var reader = rd.createInterface(fs.createReadStream(sshConfigPath)) + reader.on("line", (l:string) => { + if (l.includes(`HostName ${host}`)) { + hasHost = true + } + + if (l.includes(`Port ${port}`)) { + hasPort = true + } + }) + + if (hasHost && hasPort) { + // the container ssh info exists + canAppendSSHConfig = false + } + } + + if (canAppendSSHConfig) { + // save the host to the local ssh config file + const newSShConfigContent = + `\nHost ${host}\n HostName ${host}\n Port ${port}\n User ${username}\n PreferredAuthentications publickey\n IdentityFile ~/.ssh/id_rsa\n `; + fs.writeFileSync(sshConfigPath, newSShConfigContent, { encoding: 'utf8', flag: 'a' }); + console.log('Host registered in local ssh config'); + } + + resolve("success"); + }); }); }