Files
smartssh/ts/smartssh.classes.sshconfig.ts
T

125 lines
3.5 KiB
TypeScript
Raw Normal View History

2022-10-11 13:05:29 +02:00
import * as plugins from './smartssh.plugins.js';
import * as helpers from './smartssh.classes.helpers.js';
import { SshKey } from './smartssh.classes.sshkey.js';
2016-06-24 20:58:55 +02:00
export type TSshStrictHostKeyChecking = boolean | 'accept-new';
export interface ISshConfigOptions {
strictHostKeyChecking?: TSshStrictHostKeyChecking;
}
export interface ISshConfigHostBlock {
host: string;
values: Record<string, string>;
}
2016-05-31 19:16:45 +02:00
export class SshConfig {
2018-09-17 22:32:31 +02:00
private _sshKeyArray: SshKey[];
private _options: ISshConfigOptions;
constructor(sshKeyArrayArg: SshKey[], optionsArg: ISshConfigOptions = {}) {
2018-09-17 22:32:31 +02:00
this._sshKeyArray = sshKeyArrayArg;
this._options = {
...optionsArg,
strictHostKeyChecking: optionsArg.strictHostKeyChecking ?? true,
};
2018-09-17 22:32:31 +02:00
}
2016-06-25 02:29:34 +02:00
2018-09-17 22:32:31 +02:00
/**
* stores a config file
*/
store(dirPathArg: string) {
const resolvedDir = helpers.resolveSshDirPath(dirPathArg);
helpers.ensureSshDirSync(resolvedDir);
const configArray: configObject[] = [];
for (const sshKey of this._sshKeyArray) {
let configString = '';
2018-09-17 22:32:31 +02:00
if (sshKey.host) {
helpers.assertSafeHost(sshKey.host);
const identityFilePath = plugins.path.join(resolvedDir, sshKey.host);
2018-09-17 22:32:31 +02:00
configString =
'Host ' +
sshKey.host +
'\n' +
' HostName ' +
sshKey.host +
'\n' +
' IdentityFile ' +
helpers.quoteSshConfigValue(identityFilePath) +
2018-09-17 22:32:31 +02:00
'\n';
if (this._options.strictHostKeyChecking !== undefined) {
const strictHostKeyChecking = this._options.strictHostKeyChecking;
configString +=
' StrictHostKeyChecking ' +
(strictHostKeyChecking === 'accept-new'
? 'accept-new'
: strictHostKeyChecking
? 'yes'
: 'no') +
'\n';
}
2018-09-17 22:32:31 +02:00
}
configArray.push({
configString: configString,
authorized: sshKey.authorized,
2022-10-11 13:05:29 +02:00
sshKey: sshKey,
2018-09-17 22:32:31 +02:00
});
2016-06-25 15:30:57 +02:00
}
2018-09-17 22:32:31 +02:00
let configFile: string = '';
for (const config of configArray) {
configFile = configFile + config.configString + '\n';
2016-05-31 19:00:52 +02:00
}
plugins.fs.writeFileSync(plugins.path.join(resolvedDir, 'config'), configFile);
plugins.fs.chmodSync(plugins.path.join(resolvedDir, 'config'), 0o600);
2018-09-17 22:32:31 +02:00
}
read(dirPathArg: string) {
const configPath = plugins.path.join(helpers.resolveSshDirPath(dirPathArg), 'config');
return plugins.fs.readFileSync(configPath, 'utf8');
}
parse(dirPathArg: string) {
return SshConfig.parse(this.read(dirPathArg));
}
static parse(configStringArg: string): ISshConfigHostBlock[] {
const blocks: ISshConfigHostBlock[] = [];
let currentBlock: ISshConfigHostBlock | undefined;
for (const rawLine of configStringArg.split(/\r?\n/)) {
const line = rawLine.trim();
if (!line || line.startsWith('#')) {
continue;
}
const [keyword, ...valueParts] = line.split(/\s+/);
const value = valueParts.join(' ');
if (!keyword || !value) {
continue;
}
if (keyword.toLowerCase() === 'host') {
if (!helpers.isSafeHost(value)) {
continue;
}
currentBlock = {
host: value,
values: {},
};
blocks.push(currentBlock);
continue;
}
if (currentBlock) {
currentBlock.values[keyword.toLowerCase()] = value;
}
}
return blocks;
2018-09-17 22:32:31 +02:00
}
}
2016-06-25 02:10:53 +02:00
2018-09-17 22:32:31 +02:00
export interface configObject {
configString: string;
authorized: boolean;
sshKey: SshKey;
}