97 lines
4.0 KiB
Rust
97 lines
4.0 KiB
Rust
// file: crates/ksp-app-wallet-desk/src/wallet_secrets.rs
|
|
// version: 1
|
|
|
|
//! Config-owned Wallet password candidate discovery for explicit unlock operations.
|
|
|
|
const WALLET_SECRET_PREFIX: &str = "KSP_SECRET_WALLET_PASS_";
|
|
|
|
/// One Config-owned secret candidate retained only inside Rust.
|
|
pub(crate) struct WalletSecretCandidate {
|
|
variable_name: String,
|
|
}
|
|
|
|
impl WalletSecretCandidate {
|
|
/// Explicitly reveals this candidate through Config's privileged management boundary.
|
|
pub(crate) fn reveal(self, management: &ksp_config_lib::ConfigManagement) -> ksp_core_lib::Result<std::option::Option<String>> {
|
|
return management.reveal_effective_environment_value(self.variable_name.as_str());
|
|
}
|
|
}
|
|
|
|
/// Discovers configured Wallet password candidates without revealing values.
|
|
pub(crate) fn discover_wallet_secret_candidates(
|
|
management: &ksp_config_lib::ConfigManagement,
|
|
wallet_id: &str,
|
|
) -> ksp_core_lib::Result<std::vec::Vec<WalletSecretCandidate>> {
|
|
let reports = management.environment_report();
|
|
let reports = match reports {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let mut names = reports
|
|
.into_iter()
|
|
.filter(|report| {
|
|
return report.sensitivity() == ksp_config_lib::ConfigSensitivity::Secret
|
|
&& report.effective_source().is_some()
|
|
&& report.variable_name().starts_with(WALLET_SECRET_PREFIX)
|
|
&& report.variable_name().len() > WALLET_SECRET_PREFIX.len();
|
|
})
|
|
.map(|report| return report.variable_name().to_owned())
|
|
.collect::<std::vec::Vec<_>>();
|
|
order_wallet_secret_candidate_names(wallet_id, names.as_mut_slice());
|
|
return std::result::Result::Ok(names.into_iter().map(|variable_name| return WalletSecretCandidate { variable_name }).collect());
|
|
}
|
|
|
|
/// Returns the number of effective configured Wallet password candidates without revealing names or values.
|
|
pub(crate) fn wallet_secret_candidate_count(management: &ksp_config_lib::ConfigManagement, wallet_id: &str) -> ksp_core_lib::Result<usize> {
|
|
let candidates = discover_wallet_secret_candidates(management, wallet_id);
|
|
return candidates.map(|values| return values.len());
|
|
}
|
|
|
|
/// Normalizes a native Wallet filename to the deterministic Config secret label candidate.
|
|
#[must_use]
|
|
fn normalize_wallet_secret_label(wallet_id: &str) -> String {
|
|
let stem = wallet_id.strip_suffix(crate::WALLET_FILE_SUFFIX).unwrap_or(wallet_id);
|
|
let mut output = String::new();
|
|
let mut previous_separator = false;
|
|
for byte in stem.bytes() {
|
|
let normalized = if byte.is_ascii_alphanumeric() { byte.to_ascii_uppercase() as char } else { '_' };
|
|
if normalized == '_' {
|
|
if output.is_empty() || previous_separator {
|
|
continue;
|
|
}
|
|
output.push('_');
|
|
previous_separator = true;
|
|
} else {
|
|
output.push(normalized);
|
|
previous_separator = false;
|
|
}
|
|
}
|
|
while output.ends_with('_') {
|
|
output.pop();
|
|
}
|
|
return output;
|
|
}
|
|
|
|
fn order_wallet_secret_candidate_names(wallet_id: &str, names: &mut [String]) {
|
|
let normalized = normalize_wallet_secret_label(wallet_id);
|
|
names.sort_by(|left, right| {
|
|
return wallet_secret_sort_key(left.as_str(), normalized.as_str()).cmp(&wallet_secret_sort_key(right.as_str(), normalized.as_str()));
|
|
});
|
|
}
|
|
|
|
fn wallet_secret_sort_key(variable_name: &str, normalized_filename: &str) -> (u8, u64, String) {
|
|
let suffix = variable_name.strip_prefix(WALLET_SECRET_PREFIX).unwrap_or(variable_name);
|
|
if suffix == normalized_filename && !normalized_filename.is_empty() {
|
|
return (0, 0, suffix.to_owned());
|
|
}
|
|
if !suffix.is_empty() && suffix.bytes().all(|byte| return byte.is_ascii_digit()) {
|
|
let parsed = suffix.parse::<u64>().unwrap_or(u64::MAX);
|
|
return (1, parsed, suffix.to_owned());
|
|
}
|
|
return (2, 0, suffix.to_owned());
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "../unit_tests/wallet_secrets.rs"]
|
|
mod tests;
|