import * as vscode from 'vscode'; import * as path from 'path'; import * as os from 'os'; import * as fs from 'fs'; const { generateKeyPairSync, createHash } = require('node:crypto'); const sshpk = require('sshpk'); export default class User { private context:vscode.ExtensionContext; private username:string|undefined; private userToken:string|undefined; private usernameKey:string = 'devstarUsername' private userTokenKey:string = 'devstarUserToken' constructor(context: vscode.ExtensionContext) { this.context = context; this.username = this.context.globalState.get(this.usernameKey); this.userToken = this.context.globalState.get(this.userTokenKey); } private isLogged() { var existUsername = false; var existUserToken = false; if(this.username != undefined && this.username != '') { existUsername = true; } if(this.userToken != undefined && this.userToken != '') { existUserToken = true; } if (existUsername && existUserToken) { return true; } else { return false; } } public getUsernameFromLocal(): string|undefined { return this.username; } public getUserTokenFromLocal(): string|undefined{ return this.userToken; } public setUsernameToLocal(username:string) { this.context.globalState.update(this.usernameKey, username); this.username = username; } public setUserTokenToLocal(userToken:string) { this.context.globalState.update(this.userTokenKey, userToken) this.userToken = userToken } public getUserPrivateKeyPath() : string{ if (!this.isLogged) { return ''; } return path.join(os.homedir(), '.ssh', `id_rsa_${this.username}`) } public getUserPublicKeyPath() :string{ if (!this.isLogged) { return ''; } return path.join(os.homedir(), '.ssh', `id_rsa_${this.username}.pub`) } public existUserPublicKey() :boolean{ const userPublicKeyPath = this.getUserPublicKeyPath(); return fs.existsSync(userPublicKeyPath) } public existUserPrivateKey() :boolean{ const userPrivateKeyPath = this.getUserPrivateKeyPath(); return fs.existsSync(userPrivateKeyPath) } public getUserPublicKey(): string { const userPublicKeyPath = this.getUserPublicKeyPath(); const userPublicKey = fs.readFileSync(userPublicKeyPath, 'utf-8'); // remove `\r` `\n` const trimmedDefaultPublicKey = userPublicKey.replace(/[\r\n]/g, ""); return trimmedDefaultPublicKey; } public getUserPrivateKey(): string { const userPrivateKey = this.getUserPrivateKeyPath(); return fs.readFileSync(userPrivateKey, 'utf-8'); } public async createUserSSHKey() { if (this.existUserPublicKey() && this.existUserPrivateKey()) { // if both public and private key exists, stop return; } const { publicKey, privateKey, } = await generateKeyPairSync('rsa', { modulusLength: 4096, publicKeyEncoding: { type: 'spki', format: 'pem', }, privateKeyEncoding: { type: 'pkcs8', format: 'pem', }, }); const publicKeyFingerprint = sshpk.parseKey(publicKey, 'pem').toString('ssh'); const publicKeyStr = publicKeyFingerprint; // public key is public key fingerprint const privateKeyStr = privateKey; try { await fs.writeFileSync(this.getUserPublicKeyPath(), publicKeyStr); await fs.writeFileSync(this.getUserPrivateKeyPath(), privateKeyStr); // limit the permission of private key to prevent that the private key not works await fs.chmodSync(this.getUserPrivateKeyPath(), 0o600) } catch(error) { console.error("Failed to write public/private key into the default ssh public/key file: ", error); } } }