Skip to content

Commit

Permalink
feat(firefox): compeleted firefox trust store implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
shubhexists committed Sep 4, 2024
1 parent 8ef8f37 commit 9cf56cc
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 18 deletions.
40 changes: 33 additions & 7 deletions core/src/commands/generate.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::{
trust_stores::{nss::NSSValue, nss_profile::NSSProfile, CAValue},
trust_stores::{
firefox::FirefoxTrustStore, nss::NSSValue, nss_profile::NSSProfile,
utils::check_if_firefox_exists, CAValue,
},
utils::{get_certificates_from_data_dir, save_generated_cert_key_files},
x509::{
ca_cert::CACert, ca_req::CAReq, distinguished_name::DistinguishedName, leaf_cert::LeafCert,
Expand Down Expand Up @@ -313,11 +316,22 @@ pub fn generate(
};
ca_value_object.install_certificate()?;
let nss_profile_object: NSSProfile = NSSProfile::new();
let ca_unique_name: String = "vanish-root-test-123456-ujjwalpppp".to_string();
let ca_unique_name: String = "vanish-root-test-123456-shubham-brr".to_string();
let caroot: String = "/home/jerry/.local/share/vanish/ca_cert.pem".to_string();
let mkcert: NSSValue = NSSValue::new(nss_profile_object, ca_unique_name, caroot);
let mkcert: NSSValue =
NSSValue::new(nss_profile_object, ca_unique_name.clone(), caroot.clone());
let success: bool = mkcert.install_nss();

let firefox_exists: bool = check_if_firefox_exists()?;
if firefox_exists {
let firefox_trust_store_object: FirefoxTrustStore =
FirefoxTrustStore::new(ca_unique_name, caroot)?;
let paths_with_trust_stores: Vec<PathBuf> =
FirefoxTrustStore::find_cert_directories(&firefox_trust_store_object)?;
FirefoxTrustStore::install_firefox_certificates(
&firefox_trust_store_object,
paths_with_trust_stores,
);
}
if success {
println!("Certificate installed successfully.");
} else {
Expand Down Expand Up @@ -454,11 +468,23 @@ pub fn generate(
};
ca_value_object.install_certificate()?;
let nss_profile_object: NSSProfile = NSSProfile::new();
let ca_unique_name: String = "vanish-root-testing-1234-ujjwal".to_string();
let ca_unique_name: String = "vanish-root-testing-1234-shubham-brr".to_string();
let caroot: String = "/home/jerry/.local/share/vanish/ca_cert.pem".to_string();
let mkcert: NSSValue = NSSValue::new(nss_profile_object, ca_unique_name, caroot);
let mkcert: NSSValue =
NSSValue::new(nss_profile_object, ca_unique_name.clone(), caroot.clone());
let success: bool = mkcert.install_nss();

let firefox_exists: bool = check_if_firefox_exists()?;
if firefox_exists {
let firefox_trust_store_object: FirefoxTrustStore =
FirefoxTrustStore::new(ca_unique_name, caroot)?;
let paths_with_trust_stores: Vec<PathBuf> =
FirefoxTrustStore::find_cert_directories(&firefox_trust_store_object)?;
println!("{:?}", paths_with_trust_stores);
FirefoxTrustStore::install_firefox_certificates(
&firefox_trust_store_object,
paths_with_trust_stores,
);
}
if success {
println!("Certificate installed successfully.");
} else {
Expand Down
3 changes: 3 additions & 0 deletions core/src/trust_stores/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ impl fmt::Display for TrustStoreError {

impl Error for TrustStoreError {}

#[derive(Debug)]
pub enum FirefoxTrustStoreError {
ENVVariableNotFound(VarError, String),
IOError(io::Error),
Expand All @@ -47,3 +48,5 @@ impl fmt::Display for FirefoxTrustStoreError {
}
}
}

impl Error for FirefoxTrustStoreError {}
100 changes: 90 additions & 10 deletions core/src/trust_stores/firefox.rs
Original file line number Diff line number Diff line change
@@ -1,47 +1,93 @@
use super::errors::FirefoxTrustStoreError;
use std::process::exit;
use std::{
env, ffi, fs, io,
env, fs, io,
path::{Path, PathBuf},
process::{Command, ExitStatus},
};

pub struct FirefoxTrustStore {
firefox_profile: Vec<String>,
certutil_path: Option<String>,
ca_unique_name: String,
vanish_ca_path: String,
}

impl FirefoxTrustStore {
pub fn new() -> Result<FirefoxTrustStore, FirefoxTrustStoreError> {
pub fn new(
ca_unique_name: String,
vanish_ca_path: String,
) -> Result<FirefoxTrustStore, FirefoxTrustStoreError> {
let mut firefox_profile: Vec<String> = Vec::<String>::new();
let mut certutil_path: Option<String> = None;

#[cfg(target_os = "linux")]
{
let home: String = env::var("HOME").map_err(|err: env::VarError| {
FirefoxTrustStoreError::ENVVariableNotFound(err, "HOME".to_string())
})?;
firefox_profile.push(home.clone() + "/.morzilla/firefox/");
firefox_profile.push(home + "/snap/firefox/common/.mozilla/firefox/");
firefox_profile.push(format!("{}/.mozilla/firefox", home));
firefox_profile.push(format!("{}/snap/firefox/common/.mozilla/firefox", home));

if Command::new("certutil").output().is_ok() {
certutil_path = Some("certutil".to_string());
}
}

#[cfg(target_os = "windows")]
{
let userprofile: String = env::var("USERPROFILE").map_err(|err: env::VarError| {
FirefoxTrustStoreError::ENVVariableNotFound(err, "USERPROFILE".to_string())
})?;
firefox_profile.push(userprofile + "\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles");
firefox_profile.push(format!(
"{}\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles",
userprofile
));

// NOT SURE
if Command::new("certutil").output().is_ok() {
certutil_path = Some("certutil".to_string());
}
}

#[cfg(target_os = "macos")]
{
let home: String = env::var("HOME").map_err(|err: env::VarError| {
FirefoxTrustStoreError::ENVVariableNotFound(err, "HOME".to_string())
})?;
firefox_profile.push(home + "/Library/Application Support/Firefox/Profiles/");
firefox_profile.push(format!(
"{}/Library/Application Support/Firefox/Profiles/",
home
));

if Command::new("certutil").output().is_ok() {
certutil_path = Some("certutil".to_string());
} else if Path::new("/usr/local/opt/nss/bin/certutil").exists() {
certutil_path = Some("/usr/local/opt/nss/bin/certutil".to_string());
} else if let Ok(out) = Command::new("brew").arg("--prefix").arg("nss").output() {
let path = String::from_utf8_lossy(&out.stdout).trim().to_string();
let full_path = format!("{}/bin/certutil", path);
if Path::new(&full_path).exists() {
certutil_path = Some(full_path);
}
}
}
Ok(FirefoxTrustStore { firefox_profile })

Ok(FirefoxTrustStore {
firefox_profile,
certutil_path,
vanish_ca_path,
ca_unique_name,
})
}

pub fn find_cert_directories(&self) -> Result<Vec<PathBuf>, FirefoxTrustStoreError> {
let mut cert_dirs: Vec<PathBuf> = Vec::new();

println!("Firefox Profiles: {:?}", &self.firefox_profile);
for profile_dir in &self.firefox_profile {
let path: &Path = Path::new(profile_dir);
println!("{:?} exists: {:?}", &path, &path.exists());
if path.exists() && path.is_dir() {
println!("Path is a dir: {:?}", &path);
for entry in fs::read_dir(path)
.map_err(|err: io::Error| FirefoxTrustStoreError::IOError(err))?
{
Expand All @@ -67,5 +113,39 @@ impl FirefoxTrustStore {
}
}

pub fn install_firefox_certificates(&self) {}
pub fn install_firefox_certificates(&self, cert_paths: Vec<PathBuf>) {
match &self.certutil_path {
Some(path) => {
for cert_dir in cert_paths {
let cmd_result: Result<ExitStatus, io::Error> = Command::new(path)
.arg("-A")
.arg("-d")
.arg(cert_dir.to_str().unwrap())
.arg("-t")
.arg("C,,")
.arg("-n")
.arg(&self.ca_unique_name)
.arg("-i")
.arg(&self.vanish_ca_path)
.status();

match cmd_result {
Ok(status) if status.success() => {
println!("Successfully installed certificate in {:?}", cert_dir);
}
Ok(_) => {
eprintln!("Failed to install certificate in {:?}", cert_dir);
}
Err(err) => {
eprintln!("Error executing certutil: {:?}", err);
}
}
}
}
None => {
eprint!("No certutil found. Please install!");
exit(1);
}
};
}
}
1 change: 1 addition & 0 deletions core/src/trust_stores/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod errors;
pub mod firefox;
pub mod nss;
pub mod nss_profile;
pub mod utils;

#[cfg(target_os = "linux")]
mod linux;
Expand Down
2 changes: 1 addition & 1 deletion core/src/trust_stores/nss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl NSSValue {
.arg("-n")
.arg(&self.ca_unique_name)
.arg("-i")
.arg(format!("{}", self.caroot))
.arg(&self.caroot)
.status();

if let Err(err) = cmd {
Expand Down
23 changes: 23 additions & 0 deletions core/src/trust_stores/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use std::{fs, io};

pub fn check_if_firefox_exists() -> Result<bool, io::Error> {
let firefox_paths: Vec<String> = vec![
"/usr/bin/firefox".to_string(),
"/usr/bin/firefox-nightly".to_string(),
"/usr/bin/firefox-developer-edition".to_string(),
"/snap/firefox".to_string(),
"/Applications/Firefox.app".to_string(),
"/Applications/FirefoxDeveloperEdition.app".to_string(),
"/Applications/Firefox Developer Edition.app".to_string(),
"/Applications/Firefox Nightly.app".to_string(),
"C:\\Program Files\\Mozilla Firefox".to_string(),
];

for path in firefox_paths {
if fs::metadata(&path).is_ok() {
return Ok(true);
}
}

Ok(false)
}

0 comments on commit 9cf56cc

Please sign in to comment.