#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
use crate::ported::errors;
use crate::ported::helpers;
use crate::ported::request::common::normalizePasswordStorePath;
use crate::ported::request::process::{request, StoreSettings};
use crate::ported::response;
use serde_json::Value;
use std::fs;
use std::io;
use std::path::PathBuf;
pub fn configure(request: &request) {
let mut responseData = response::MakeConfigureResponse();
if !request.Settings.GpgPath.is_empty() { let err = helpers::ValidateGpgBinary(&request.Settings.GpgPath); if let Err(e) = err { eprintln!( "The provided gpg binary path '{}' is invalid: {}",
request.Settings.GpgPath, e,
);
response::SendErrorAndExit( errors::Code::InvalidGpgPath,
Some(response::params_of(&[
(errors::field::MESSAGE, "The provided gpg binary path is invalid"),
(errors::field::ACTION, "configure"),
(errors::field::ERROR, &e),
(errors::field::GPG_PATH, &request.Settings.GpgPath),
])),
);
}
}
for store in request.Settings.Stores.values() { let mut store = store.clone(); let normalizedStorePath = match normalizePasswordStorePath(&store.Path) { Ok(p) => p,
Err(e) => { eprintln!( "The password store '{:?}' is not accessible at its location: {}",
store, e
);
response::SendErrorAndExit( errors::Code::InaccessiblePasswordStore,
Some(response::params_of(&[
(errors::field::MESSAGE, "The password store is not accessible"),
(errors::field::ACTION, "configure"),
(errors::field::ERROR, &e),
(errors::field::STORE_ID, &store.ID),
(errors::field::STORE_NAME,&store.Name),
(errors::field::STORE_PATH,&store.Path),
])),
);
}
};
store.Path = normalizedStorePath.to_string_lossy().into_owned();
let settings_raw = readDefaultSettings(&normalizedStorePath); let mut store_err: Option<String> = None;
let raw_string = match settings_raw {
Ok(s) => s,
Err(e) => {
store_err = Some(e);
String::new()
}
};
if store_err.is_none() { if let Err(e) = serde_json::from_str::<Value>(&raw_string) {
store_err = Some(e.to_string());
} else {
let _: Result<StoreSettings, _> = serde_json::from_str(&raw_string);
}
}
responseData.StoreSettings.insert(store.ID.clone(), raw_string);
if let Some(e) = store_err { eprintln!( "Unable to read .browserpass.json of the user-configured password store '{:?}': {}",
store, e
);
response::SendErrorAndExit( errors::Code::UnreadablePasswordStoreDefaultSettings,
Some(response::params_of(&[
(errors::field::MESSAGE, "Unable to read .browserpass.json of the password store"),
(errors::field::ACTION, "configure"),
(errors::field::ERROR, &e),
(errors::field::STORE_ID, &store.ID),
(errors::field::STORE_NAME, &store.Name),
(errors::field::STORE_PATH, &store.Path),
])),
);
}
}
if request.Settings.Stores.is_empty() { let possibleDefaultStorePath = match getDefaultPasswordStorePath() { Ok(p) => p,
Err(e) => { eprintln!("Unable to determine the location of the default password store: {e}"); response::SendErrorAndExit( errors::Code::UnknownDefaultPasswordStoreLocation,
Some(response::params_of(&[
(errors::field::MESSAGE, "Unable to determine the location of the default password store"),
(errors::field::ACTION, "configure"),
(errors::field::ERROR, &e),
])),
);
}
};
let possiblePathStr = possibleDefaultStorePath.to_string_lossy().into_owned();
let normalized = match normalizePasswordStorePath(&possiblePathStr) { Ok(p) => p,
Err(e) => { eprintln!( "The default password store is not accessible at the location '{possiblePathStr}': {e}"
);
response::SendErrorAndExit( errors::Code::InaccessibleDefaultPasswordStore,
Some(response::params_of(&[
(errors::field::MESSAGE, "The default password store is not accessible"),
(errors::field::ACTION, "configure"),
(errors::field::ERROR, &e),
(errors::field::STORE_PATH, &possiblePathStr),
])),
);
}
};
responseData.DefaultStore.Path = normalized.to_string_lossy().into_owned();
let default_raw = match readDefaultSettings(&normalized) { Ok(s) => Some(s),
Err(e) => {
emitUnreadableDefault(&responseData.DefaultStore.Path, &e);
}
};
if let Some(raw_string) = default_raw {
if let Err(e) = serde_json::from_str::<Value>(&raw_string) {
emitUnreadableDefault(&responseData.DefaultStore.Path, &e.to_string());
} else {
let _: Result<StoreSettings, _> = serde_json::from_str(&raw_string);
}
responseData.DefaultStore.Settings = raw_string;
}
}
response::SendOk(responseData); }
fn emitUnreadableDefault(store_path: &str, e: &str) -> ! {
eprintln!(
"Unable to read .browserpass.json of the default password store in '{store_path}': {e}"
);
response::SendErrorAndExit( errors::Code::UnreadableDefaultPasswordStoreDefaultSettings,
Some(response::params_of(&[
(errors::field::MESSAGE, "Unable to read .browserpass.json of the default password store"),
(errors::field::ACTION, "configure"),
(errors::field::ERROR, e),
(errors::field::STORE_PATH, store_path),
])),
);
}
pub fn getDefaultPasswordStorePath() -> Result<PathBuf, String> {
let path = std::env::var("PASSWORD_STORE_DIR").unwrap_or_default(); if !path.is_empty() { return Ok(PathBuf::from(path)); }
let home = match dirs_home() { Ok(h) => h,
Err(e) => return Err(format!("{e}")), };
let path = PathBuf::from(home).join(".password-store"); Ok(path) }
fn dirs_home() -> Result<String, io::Error> {
std::env::var("HOME")
.map_err(|_| io::Error::new(io::ErrorKind::NotFound, "$HOME not set"))
}
pub fn readDefaultSettings(storePath: &std::path::Path) -> Result<String, String> {
let p = storePath.join(".browserpass.json"); match fs::read_to_string(&p) { Ok(content) => Ok(content), Err(e) if e.kind() == io::ErrorKind::NotFound => Ok("{}".to_string()), Err(e) => Err(format!("{e}")), }
}
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
const _: () = ();