use crate::compat::host::Host;
use crate::compat::unzip::ttyio::Password;
use super::Zr;
pub(crate) const IZ_PWLEN: usize = 80;
#[cfg(test)]
thread_local! {
pub(crate) static TYPED: std::cell::RefCell<std::collections::VecDeque<Vec<u8>>> =
const { std::cell::RefCell::new(std::collections::VecDeque::new()) };
}
pub(crate) fn getp(z: &mut Zr, prompt: &[u8]) -> Option<Password> {
if matches!(z.host, Host::Sandbox(_)) {
#[cfg(test)]
if let Some(answer) = TYPED.with(|t| t.borrow_mut().pop_front()) {
let _ = z.err.write_all(prompt);
let _ = z.err.write_all(b"\n");
return Some(Password::new(&answer));
}
return None;
}
#[cfg(unix)]
{
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
let f = unsafe { libc::open(c"/dev/tty".as_ptr(), libc::O_RDONLY | libc::O_CLOEXEC) };
if f == -1 {
return None;
}
let f = unsafe { OwnedFd::from_raw_fd(f) };
crate::compat::unzip::ttyio::getp_on(&mut *z.err, f.as_raw_fd(), prompt, IZ_PWLEN + 1).ok()
}
#[cfg(not(unix))]
{
let _ = prompt;
None
}
}
#[cfg(unix)]
pub(crate) fn random_header() -> std::io::Result<[u8; 10]> {
let mut b = [0u8; 10];
#[cfg(any(
target_vendor = "apple",
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly"
))]
if unsafe { libc::getentropy(b.as_mut_ptr().cast(), b.len()) } == 0 {
return Ok(b);
}
#[cfg(any(target_os = "linux", target_os = "android"))]
{
let mut got = 0;
while got < b.len() {
let n = unsafe { libc::getrandom(b[got..].as_mut_ptr().cast(), b.len() - got, 0) };
if n > 0 {
got += n as usize;
} else if n < 0
&& std::io::Error::last_os_error().kind() == std::io::ErrorKind::Interrupted
{
continue;
} else {
break;
}
}
if got == b.len() {
return Ok(b);
}
}
use std::io::Read;
std::fs::File::open("/dev/urandom").and_then(|mut f| f.read_exact(&mut b))?;
Ok(b)
}
#[cfg(not(unix))]
pub(crate) fn random_header() -> std::io::Result<[u8; 10]> {
Err(std::io::Error::from(std::io::ErrorKind::Unsupported))
}