extern crate libc;
extern crate rand;
extern crate seckey;
extern crate termion;
extern crate sha3;
pub mod readtty;
pub mod colorhash;
use std::io::{ self, Read, Write };
use std::iter::repeat;
use rand::random;
use seckey::SecKey;
use termion::clear;
use termion::get_tty;
use termion::event::Key;
use termion::color::{ Fg, Reset, AnsiValue };
use colorhash::{ hash_as_ansi, hash_chars_as_ansi };
use readtty::{ RawTTY, read_from_tty };
#[inline]
pub fn askpass<F>(prompt: &str, f: F)
-> io::Result<()>
where F: FnOnce(&[char]) -> io::Result<()>
{
raw_askpass(&mut RawTTY::new()?, &mut get_tty()?, prompt, '*')
.and_then(|(buf, pos)| f(&buf.read()[..pos]))
}
pub fn raw_askpass(input: &mut Read, output: &mut Write, prompt: &str, star: char)
-> io::Result<(SecKey<[char; 256]>, usize)>
{
let mut pos = 0;
let mut buf = SecKey::new([char::default(); 256])
.map_err(|_| io::Error::new(io::ErrorKind::Other, "SecKey malloc fail"))?;
read_from_tty(input, |key| {
let mut buf = buf.write();
match key {
Key::Char('\n') => return Ok(true),
Key::Char(c) => if pos < buf.len() {
buf[pos] = c;
pos += 1;
},
Key::Backspace | Key::Delete if pos >= 1 => pos -= 1,
Key::Ctrl('c') => return Err(io::Error::new(io::ErrorKind::Interrupted, "Ctrl-c")),
Key::Null => (),
_ => return Ok(false)
}
let colors = match pos {
0 => [AnsiValue(30); 8],
1...7 => hash_as_ansi(&[random(), random(), random()]),
p => hash_chars_as_ansi(&buf[..p])
};
write!(
output,
"\r{} {}{}",
prompt,
repeat(star)
.take(4)
.zip(&colors[..4])
.map(|(star, &color)| format!("{}{}{}", Fg(color), star, star))
.collect::<String>(),
Fg(Reset)
)?;
Ok(false)
})?;
write!(output, "{}\r", clear::CurrentLine)?;
Ok((buf, pos))
}