~sircmpwn/himitsu-ssh

e86b4e9dd2af09067aefbb4c50e0547a9eead9a5 — Armin Preiml 2 months ago 01b8634
refactor hissh-import

 * Use himitsu::{client,query}
 * Replace bufio::read_line with scanner
 * Keep asking on badpass
1 files changed, 59 insertions(+), 40 deletions(-)

M cmd/hissh-import/main.ha
M cmd/hissh-import/main.ha => cmd/hissh-import/main.ha +59 -40
@@ 2,9 2,12 @@ use bufio;
use bytes;
use dirs;
use encoding::base64;
use encoding::utf8;
use fmt;
use format::ssh;
use getopt;
use himitsu::client;
use himitsu::query;
use io;
use net::unix;
use net;


@@ 63,7 66,7 @@ export fn main() void = {

	let buf = memio::dynamic();
	defer io::close(&buf)!;
	fmt::fprintf(&buf, "add proto=ssh type={} pkey='", ssh::key_format(privkey))!;
	fmt::fprintf(&buf, "proto=ssh type={} pkey='", ssh::key_format(privkey))!;
	let b64 = base64::newencoder(&base64::std_encoding, &buf);
	ssh::key_encoderawpub(privkey, &b64)!;
	io::close(&b64)!;


@@ 77,31 80,40 @@ export fn main() void = {
		shlex::quote(&buf, privkey.comment)!;
	};
	fmt::fprintln(&buf)!;
	let q = match (query::parse_str(memio::string(&buf)!)) {
	case let q: query::query =>
		yield q;
	case let e: query::error =>
		fmt::fatal("Error preparing query:", query::strerror(e));
	};
	defer query::finish(&q);

	// TODO: It would be nice if himitsu (library) provided some tools for
	// connecting to and interacting with a Himitsu socket
	let path = path::init()!;
	const sockpath = path::set(&path, dirs::runtime()!, "himitsu")!;
	let conn = match (unix::connect(sockpath)) {
	let conn = match (client::connect()) {
	case let s: net::socket =>
		yield s;
	case let e: net::error =>
		fmt::fatal("Error connecting to Himitsu:", net::strerror(e));
	case let e: client::error =>
		fmt::fatal("Error connecting to Himitsu:", client::strerror(e));
	};
	defer io::close(conn)!;

	io::writeall(conn, memio::buffer(&buf))!;
	match (client::query(conn, client::operation::ADD, &q, 0)) {
	case let i: client::keyiter =>
		let k = match (client::next(&i)) {
		case let k: query::query =>
			yield k;
		case done =>
			fmt::fatal("Error adding key: empty result");
		case let e: client::error =>
			fmt::fatal("Error adding key:", client::strerror(e));
		};
		query::unparse(os::stdout, &k)!;

	match (bufio::read_line(conn)) {
	case io::EOF =>
		fmt::fatal("Unexpected EOF from Himitsu");
	case let err: io::error =>
		fmt::fatal("Error reading from Himitsu:", io::strerror(err));
	case let line: []u8 =>
		defer free(line);
		io::writeall(os::stdout, line)!;
		if (!(client::next(&i) is done)) {
			fmt::fatal("Internal error: End not received");
		};
	case let e: client::error =>
		fmt::fatal("Error adding key:", client::strerror(e));
	};
	fmt::println()!;
};

fn decrypt(key: *ssh::sshprivkey) void = {


@@ 112,29 124,36 @@ fn decrypt(key: *ssh::sshprivkey) void = {
		fmt::fatal("Error opening tty:", tty::strerror(err));
	};

	let scan = &bufio::newscanner(tty);
	defer bufio::finish(scan);

	const termios = tty::termios_query(tty)!;
	tty::noecho(&termios)!;

	fmt::errorf("Enter SSH key passphrase: ")!;
	const pass = bufio::read_line(tty)!;
	tty::termios_restore(&termios);
	fmt::errorln()!;

	const pass = match (pass) {
	case io::EOF =>
		fmt::fatal("Unexpected EOF");
	case let buf: []u8 =>
		yield buf;
	};
	defer {
		bytes::zero(pass);
		free(pass);
	};

	match (ssh::decrypt(key, pass)) {
	case void =>
		return;
	case let err: ssh::error =>
		fmt::fatal("Decryption failed:", ssh::strerror(err));
	for (true) {
		tty::noecho(&termios)!;

		fmt::errorf("Enter SSH key passphrase: ")!;
		const pass = bufio::scan_line(scan)!;
		tty::termios_restore(&termios);
		fmt::errorln()!;

		const pass = match (pass) {
		case io::EOF =>
			fmt::fatal("Unexpected EOF");
		case let buf: const str =>
			yield strings::toutf8(buf);
		};
		defer {
			bytes::zero(pass);
		};

		match (ssh::decrypt(key, pass)) {
		case void =>
			return;
		case ssh::badpass =>
			fmt::println("Wrong password")!;
		case let err: ssh::error =>
			fmt::fatal("Decryption failed:", ssh::strerror(err));
		};
	};
};