use std::io::Read;
use std::path::PathBuf;
use std::process::{Child, Command, ExitStatus, Stdio};
use std::{fmt, fs};
use crate::error::Error;
pub fn generate_tls_data(
temp_dir: &(String, PathBuf),
) -> Result<((String, PathBuf), String), Error> {
fn err<M: fmt::Display>(which: bool, op: &'static str, more: M) -> Error {
Error(format!(
"{} {}: {}",
op,
if which {
"TLS key generation process"
} else {
"TLS identity generation process"
},
more
))
}
fn exit_err(which: bool, process: &mut Child, exitc: &ExitStatus) -> Error {
let mut stdout = String::new();
let mut stderr = String::new();
if process
.stdout
.as_mut()
.unwrap()
.read_to_string(&mut stdout)
.is_err()
{
stdout = "<error getting process stdout>".to_string();
}
if process
.stderr
.as_mut()
.unwrap()
.read_to_string(&mut stderr)
.is_err()
{
stderr = "<error getting process stderr>".to_string();
}
err(
which,
"Exiting",
format_args!(
"{};\nstdout: ```\n{}```;\nstderr: ```\n{}```",
exitc, stdout, stderr
),
)
}
let tls_dir = temp_dir.1.join("tls");
fs::create_dir_all(&tls_dir)
.map_err(|err| Error(format!("Creating temporary directory: {}", err)))?;
let mut child = Command::new("openssl")
.args([
"req", "-x509", "-newkey", "rsa:4096", "-nodes", "-keyout", "tls.key", "-out",
"tls.crt", "-days", "3650", "-utf8",
])
.current_dir(&tls_dir)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.map_err(|error| err(true, "Spawning", error))?;
child
.stdin
.as_mut()
.unwrap()
.write_all(
concat!(
"PL\nhpip\n",
env!("CARGO_PKG_VERSION"),
"\nhpip\nhpip\nhpip/",
env!("CARGO_PKG_VERSION"),
"\nhpip@localhost\n"
)
.as_bytes(),
)
.map_err(|error| err(true, "Piping", error))?;
let es = child.wait().map_err(|error| err(true, "Waiting", error))?;
if !es.success() {
return Err(exit_err(true, &mut child, &es));
}
let mut child = Command::new("openssl")
.args([
"pkcs12",
"-export",
"-out",
"tls.p12",
"-inkey",
"tls.key",
"-in",
"tls.crt",
"-passin",
"pass:",
"-passout",
if cfg!(target_os = "macos") {
"pass:password"
} else {
"pass:"
},
])
.current_dir(&tls_dir)
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.map_err(|error| err(false, "Spawning", error))?;
let es = child.wait().map_err(|error| err(false, "Waiting", error))?;
if !es.success() {
return Err(exit_err(false, &mut child, &es));
}
Ok((
(
format!("{}/tls/tls.p12", temp_dir.0),
tls_dir.join("tls.p12"),
),
if cfg!(target_os = "macos") {
"password"
} else {
""
}
.to_string(),
))
}
use std::io::Write;