feat(sshclient): add a promise-first SSH client with secure host verification and improve SSH key/config handling
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import * as plugins from './smartssh.plugins.js';
|
||||
import * as helpers from './smartssh.classes.helpers.js';
|
||||
|
||||
export type TSshKeyType = 'duplex' | 'private' | 'public';
|
||||
|
||||
export class SshKey {
|
||||
private _privKey: string;
|
||||
private _pubKey: string;
|
||||
@@ -15,6 +17,9 @@ export class SshKey {
|
||||
) {
|
||||
this._privKey = optionsArg.private ?? '';
|
||||
this._pubKey = optionsArg.public ?? '';
|
||||
if (optionsArg.host) {
|
||||
helpers.assertSafeHost(optionsArg.host);
|
||||
}
|
||||
this._hostVar = optionsArg.host ?? '';
|
||||
this._authorized = optionsArg.authorized ?? false;
|
||||
}
|
||||
@@ -24,6 +29,9 @@ export class SshKey {
|
||||
return this._hostVar;
|
||||
}
|
||||
set host(hostArg: string) {
|
||||
if (hostArg) {
|
||||
helpers.assertSafeHost(hostArg);
|
||||
}
|
||||
this._hostVar = hostArg;
|
||||
}
|
||||
|
||||
@@ -69,7 +77,7 @@ export class SshKey {
|
||||
/**
|
||||
* returns wether there is a private, a public or both keys
|
||||
*/
|
||||
get type() {
|
||||
get type(): TSshKeyType | undefined {
|
||||
if (this._privKey && this._pubKey) {
|
||||
return 'duplex';
|
||||
} else if (this._privKey) {
|
||||
@@ -78,25 +86,68 @@ export class SshKey {
|
||||
return 'public';
|
||||
}
|
||||
}
|
||||
set type(someVlueArg: any) {
|
||||
console.log('the type of an SshKey connot be set. This value is autocomputed.');
|
||||
}
|
||||
|
||||
// methods
|
||||
read(filePathArg: string) {}
|
||||
read(filePathArg: string) {
|
||||
const resolvedPath = plugins.path.resolve(filePathArg);
|
||||
const fileName = plugins.path.basename(resolvedPath);
|
||||
const isPublicKey = fileName.endsWith('.pub');
|
||||
const host = isPublicKey ? fileName.slice(0, -4) : fileName;
|
||||
helpers.assertSafeHost(host);
|
||||
|
||||
this._hostVar = host;
|
||||
if (isPublicKey) {
|
||||
this._pubKey = plugins.fs.readFileSync(resolvedPath, 'utf8');
|
||||
} else {
|
||||
this._privKey = plugins.fs.readFileSync(resolvedPath, 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
static fromFile(filePathArg: string) {
|
||||
const sshKey = new SshKey();
|
||||
sshKey.read(filePathArg);
|
||||
return sshKey;
|
||||
}
|
||||
|
||||
static fromFiles(optionsArg: { privateKeyPath?: string; publicKeyPath?: string; host?: string }) {
|
||||
const sshKey = new SshKey({ host: optionsArg.host });
|
||||
if (optionsArg.privateKeyPath) {
|
||||
sshKey.privKey = plugins.fs.readFileSync(plugins.path.resolve(optionsArg.privateKeyPath), 'utf8');
|
||||
if (!sshKey.host) {
|
||||
const fileName = plugins.path.basename(optionsArg.privateKeyPath);
|
||||
helpers.assertSafeHost(fileName);
|
||||
sshKey.host = fileName;
|
||||
}
|
||||
}
|
||||
if (optionsArg.publicKeyPath) {
|
||||
sshKey.pubKey = plugins.fs.readFileSync(plugins.path.resolve(optionsArg.publicKeyPath), 'utf8');
|
||||
if (!sshKey.host) {
|
||||
const fileName = plugins.path.basename(optionsArg.publicKeyPath).replace(/\.pub$/, '');
|
||||
helpers.assertSafeHost(fileName);
|
||||
sshKey.host = fileName;
|
||||
}
|
||||
}
|
||||
return sshKey;
|
||||
}
|
||||
|
||||
async store(dirPathArg: string) {
|
||||
plugins.fs.ensureDirSync(dirPathArg);
|
||||
let fileNameBase = this.host;
|
||||
this.storeSync(dirPathArg);
|
||||
}
|
||||
|
||||
storeSync(dirPathArg: string) {
|
||||
helpers.assertSafeHost(this.host);
|
||||
const resolvedDir = helpers.resolveSshDirPath(dirPathArg);
|
||||
helpers.ensureSshDirSync(resolvedDir);
|
||||
const fileNameBase = this.host;
|
||||
if (this._privKey) {
|
||||
let filePath = plugins.path.join(dirPathArg, fileNameBase);
|
||||
const filePath = plugins.path.join(resolvedDir, fileNameBase);
|
||||
plugins.fs.writeFileSync(filePath, this._privKey);
|
||||
plugins.fs.chmodSync(filePath, 0o600);
|
||||
}
|
||||
if (this._pubKey) {
|
||||
let filePath = plugins.path.join(dirPathArg, fileNameBase + '.pub');
|
||||
const filePath = plugins.path.join(resolvedDir, fileNameBase + '.pub');
|
||||
plugins.fs.writeFileSync(filePath, this._pubKey);
|
||||
plugins.fs.chmodSync(filePath, 0o600);
|
||||
plugins.fs.chmodSync(filePath, 0o644);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user