overhaul identity file detection and resolution

This commit is contained in:
Siddharth Singh 2024-09-30 02:38:32 +05:30
parent 7ce1b9e2b7
commit f452e8324f
No known key found for this signature in database
3 changed files with 64 additions and 17 deletions

View file

@ -7,18 +7,19 @@ async function main() {
.subcommand(tribe)
.subcommand(remote)
.option('-i --identity-file', {
description: 'The ssh identity file to use. Defaults to ~/.ssh/id_rsa.',
default: await defaultIdentityFile(),
description: 'The ssh identity file to use. You will be prompted if this is not supplied.',
});
const { parsed } = tribes.parse(Deno.args);
parsed['identity-file'] = await defaultIdentityFile(parsed['identity-file'] as string);
const [s, v] = parsed._.slice(1);
let cmd = tribes;
if (s) cmd = tribes.getSubcommand(s);
if (v) cmd = cmd.getSubcommand(v);
await cmd.action(parsed);
await cmd.doAction(parsed);
}
if (import.meta.main) {

View file

@ -1,18 +1,7 @@
import { join } from '@std/path';
import { ParsedArgs } from './parsing.ts';
import { Command } from './command.ts';
export const defaultIdentityFile = async () => {
const home = Deno.env.get('HOME');
if (!home) throw new Error('tribes-cli: unable to find default identity file');
const path = join(home, '.ssh', 'id_rsa');
try {
await Deno.stat(path);
return path;
} catch {}
throw new Error('tribes-cli: unable to find default identity file.');
};
import { defaultIdentityFile } from './ssh/identity.ts';
import { connect } from './ssh/mod.ts';
export type Option =
& { description: string }
@ -27,5 +16,5 @@ export const cleanArg = (arg: string) => {
return arg.replace(/^--?/g, '');
};
export { Command };
export { Command, connect, defaultIdentityFile };
export type { ParsedArgs };

View file

@ -0,0 +1,57 @@
import { join } from '@std/path';
import { expandGlob } from '@std/fs/expand-glob';
import question from 'question-deno';
const resolveIdentityFile = async () => {
const home = Deno.env.get('HOME');
if (!home) throw new Error('tribes-cli: unable to find default identity file');
const path = join(home, '.ssh', '*.pub');
const found: string[] = [];
for await (const file of expandGlob(path)) {
try {
const pkey = file.path.replace(/.pub$/, '');
const info = await Deno.stat(pkey);
if (info.isFile) found.push(pkey);
} catch {}
}
if (found.length) {
const chosen = await question('list', 'There were multiple ssh keys found. Which do you want to use?', [
...found,
'Something else',
]);
if (chosen?.startsWith('/')) return chosen;
}
const input = await question('input', 'Enter the path of the ssh identity file to use.');
try {
const stat = await Deno.stat(input || '');
if (stat.isFile) return input!;
} catch {
throw new Error(`tribes-cli: could not stat "${input}"`);
}
throw new Error('tribes-cli: unable to find valid identity file, or selected path is a directory');
};
export const defaultIdentityFile = async (supplied?: string) => {
const cached = localStorage.getItem('identity-file-path');
if (cached && cached !== supplied && await question('confirm', `Found identity file ${cached}. Use it?`)) {
return cached;
}
let identityFile = '';
if (supplied) {
try {
const stat = await Deno.stat(supplied);
if (stat.isFile) identityFile = supplied;
} catch {
throw new Error(`tribes-cli: supplied identity file ${supplied} does not exist or is not a file.`);
}
}
if (!identityFile) identityFile = await resolveIdentityFile();
localStorage.setItem('identity-file-path', identityFile);
return identityFile;
};