Skip to content

Commit

Permalink
feat: moved to tee for wrtiting system certs
Browse files Browse the repository at this point in the history
  • Loading branch information
shubhexists committed Sep 5, 2024
1 parent 7e4e6fe commit 55e98cc
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 30 deletions.
5 changes: 3 additions & 2 deletions core/src/commands/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ use std::{
};

pub fn generate_install(cert: &X509) -> Result<(), Box<dyn Error>> {
let caroot: String = "/home/jerry/.local/share/vanish/ca_cert.pem".to_string();
let ca_unique_name: String = get_unique_hash(&caroot)?;
let ca_value_object: CAValue = CAValue {
ca_uniques_name: ca_unique_name.clone(),
certificate: cert.clone(),
};
ca_value_object.install_certificate()?;
let nss_profile_object: NSSProfile = NSSProfile::new();
let caroot: String = "/home/jerry/.local/share/vanish/ca_cert.pem".to_string();
let ca_unique_name: String = get_unique_hash(&caroot)?;
let mkcert: NSSValue =
NSSValue::new(nss_profile_object, ca_unique_name.clone(), caroot.clone());
let success: bool = mkcert.install_nss();
Expand Down
11 changes: 3 additions & 8 deletions core/src/trust_stores/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{env::VarError, error::Error, fmt, io};
pub enum TrustStoreError {
PEMFileCreationError(io::Error),
PEMEncodingError(ErrorStack),
WriteToFileError(io::Error),
CommandError(String),
}

impl fmt::Display for TrustStoreError {
Expand All @@ -28,13 +28,8 @@ impl fmt::Display for TrustStoreError {
err
)
}
Self::WriteToFileError(err) => {
write!(
f,
"{}: Trust Store Writing to PEM file: {}",
"Error".red(),
err
)
Self::CommandError(desc) => {
write!(f, "{}", desc)
}
}
}
Expand Down
113 changes: 93 additions & 20 deletions core/src/trust_stores/linux.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use super::errors::TrustStoreError;
use colored::*;
use openssl::error::ErrorStack;
use openssl::x509::X509;
use std::fs;
use std::fs::File;
use std::io;
use std::io::Write;
use std::path::{Path, PathBuf};

use super::errors::TrustStoreError;
use std::process::{Command, ExitStatus, Stdio};

pub struct CAValue {
pub ca_uniques_name: String,
pub certificate: X509,
}

Expand All @@ -31,23 +31,36 @@ impl CAValue {
None
}

fn is_certificate_installed(&self, pem_path: &Path) -> bool {
if pem_path.exists() {
println!(
"{}: Certificate already exists in {}",
"Info".blue(),
pem_path.display()
);
true
} else {
false
}
}

pub fn install_certificate(&self) -> Result<(), TrustStoreError> {
let store: Option<PossibleStores> = CAValue::get_available_path();
match store {
Some(store) => {
let path: String = store.get_path();
println!("{}: Adding file to trust store: {}", "Note".green(), path);
let pem_path: PathBuf = Path::new(&path).join("vanish-root.crt");
let pem_path: PathBuf =
Path::new(&path).join(format!("ca_{}.pem", self.ca_uniques_name));

if let Err(err) = fs::create_dir_all(&path) {
eprintln!("Failed to create directory: {}. Error: {}", path, err);
return Err(TrustStoreError::PEMFileCreationError(err));
if self.is_certificate_installed(&pem_path) {
println!("{}: Certificate already installed.", "Note".green());
return Ok(());
}

match CAValue::save_cert(&self.certificate, pem_path.to_str().unwrap()) {
Ok(_) => println!("Certificate saved at: {}", pem_path.display()),
Err(err) => eprintln!("{}", err),
}
self.write_certificate_with_tee(&pem_path)?;

self.run_update_certs_command(store);
}
None => {
eprintln!("Your system is not supported by Vanish yet.");
Expand All @@ -57,17 +70,77 @@ impl CAValue {
Ok(())
}

fn save_cert(cert: &X509, path: &str) -> Result<(), TrustStoreError> {
let mut file: File = File::create(path)
.map_err(|err: io::Error| TrustStoreError::PEMFileCreationError(err))?;
file.write_all(
&cert
.to_pem()
.map_err(|err: ErrorStack| TrustStoreError::PEMEncodingError(err))?,
)
.map_err(|err: io::Error| TrustStoreError::WriteToFileError(err))?;
fn write_certificate_with_tee(&self, pem_path: &Path) -> Result<(), TrustStoreError> {
let cert_pem = self
.certificate
.to_pem()
.map_err(|err: ErrorStack| TrustStoreError::PEMEncodingError(err))?;

let mut tee_cmd = Command::new("sudo")
.arg("tee")
.arg(pem_path.to_str().unwrap())
.stdin(Stdio::piped())
.stdout(Stdio::null())
.spawn()
.map_err(|err: io::Error| {
TrustStoreError::CommandError(format!(
"{}: Failed to run sudo tee: {}",
"Error".red(),
err
))
})?;

tee_cmd
.stdin
.as_mut()
.ok_or(TrustStoreError::CommandError(
"Failed to open tee stdin".to_string(),
))?
.write_all(&cert_pem)
.map_err(|err: io::Error| {
TrustStoreError::PEMFileCreationError(io::Error::new(io::ErrorKind::Other, err))
})?;

let status = tee_cmd.wait().map_err(|err| {
TrustStoreError::CommandError(format!(
"{}: Failed to wait for tee: {}",
"Error".red(),
err
))
})?;

if !status.success() {
return Err(TrustStoreError::CommandError(
"Tee command failed".to_string(),
));
}

Ok(())
}

fn run_update_certs_command(&self, store: PossibleStores) {
let (cmd, arg) = match store {
PossibleStores::RedHat => ("sudo", "update-ca-trust"),
PossibleStores::Debian => ("sudo", "update-ca-certificates"),
PossibleStores::SuSE => ("sudo", "update-ca-certificates"),
_ => return,
};

let output: Result<ExitStatus, io::Error> =
Command::new(cmd).arg(arg).stdout(Stdio::null()).status();

match output {
Ok(status) if status.success() => {
println!("{}: {} completed successfully", "Success".green(), arg)
}
Ok(_) => eprintln!(
"{}: {} failed. Please try running the command with elevated permissions.",
"Error".red(),
arg
),
Err(err) => eprintln!("{}: Failed to run {}: {:?}", "Error".red(), arg, err),
}
}
}

enum PossibleStores {
Expand Down

0 comments on commit 55e98cc

Please sign in to comment.