use std::path::PathBuf;
use super::ServerId;
pub fn login_home_dir() -> Option<PathBuf> {
#[cfg(unix)]
let home = nix::unistd::User::from_uid(nix::unistd::Uid::current())
.ok()
.flatten()
.map(|user| user.dir);
#[cfg(not(unix))]
let home = dirs::home_dir();
home.and_then(|home| dunce::canonicalize(home).ok())
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum WorkspaceTrust {
#[default]
Trusted,
Untrusted(ServerAllowlist),
}
impl WorkspaceTrust {
#[must_use]
pub fn untrusted(allowed: impl IntoIterator<Item = ServerId>) -> Self {
Self::Untrusted(ServerAllowlist::new(allowed))
}
#[must_use]
pub fn allows(&self, id: &ServerId) -> bool {
match self {
Self::Trusted => true,
Self::Untrusted(allowlist) => allowlist.contains(id),
}
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ServerAllowlist(Vec<ServerId>);
impl ServerAllowlist {
#[must_use]
pub fn new(allowed: impl IntoIterator<Item = ServerId>) -> Self {
let mut ids: Vec<ServerId> = Vec::new();
for id in allowed {
if !ids.contains(&id) {
ids.push(id);
}
}
Self(ids)
}
#[must_use]
pub fn contains(&self, id: &ServerId) -> bool {
self.0.contains(id)
}
#[must_use]
pub fn as_slice(&self) -> &[ServerId] {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_is_trusted_and_allows_everything() {
assert_eq!(WorkspaceTrust::default(), WorkspaceTrust::Trusted);
assert!(WorkspaceTrust::Trusted.allows(&ServerId::from_static("anything")));
}
#[test]
fn test_untrusted_allows_only_listed_ids() {
let trust = WorkspaceTrust::untrusted([ServerId::from_static("rust")]);
assert!(trust.allows(&ServerId::from_static("rust")));
assert!(!trust.allows(&ServerId::from_static("python")));
assert!(!WorkspaceTrust::untrusted([]).allows(&ServerId::from_static("rust")));
}
#[test]
fn test_allowlist_deduplicates_keeping_first_occurrence() {
let list = ServerAllowlist::new(["b", "a", "b", "a"].map(ServerId::from_static));
assert_eq!(list.as_slice(), ["b", "a"].map(ServerId::from_static));
}
}