strop_engine/session/
trust.rs1use super::{persistence, SessionError};
3use crate::files::FileTarget;
4use std::path::{Path, PathBuf};
5
6fn path(base: Option<&Path>) -> Option<PathBuf> {
7 base.map(|base| base.join("strop").join("trusted-projects"))
8}
9
10fn load(path: &Path) -> Result<Vec<FileTarget>, SessionError> {
11 let bytes = match persistence::read(path) {
12 Ok(bytes) => bytes,
13 Err(SessionError::Io { source, .. }) if source.kind() == std::io::ErrorKind::NotFound => {
14 return Ok(Vec::new())
15 }
16 Err(error) => return Err(error),
17 };
18 if bytes.first() == Some(&b'[') {
19 return Ok(serde_json::from_slice(&bytes)?);
20 }
21 let text = std::str::from_utf8(&bytes).map_err(|e| SessionError::Invalid(e.to_string()))?;
23 text.lines()
24 .map(|line| {
25 if line.contains('\u{fffd}') {
26 return Err(strop_core::path_serde::PathError::AmbiguousLegacy.into());
27 }
28 let root = PathBuf::from(line);
29 strop_core::path_serde::validate(&root)?;
30 Ok(FileTarget::Local(root))
31 })
32 .collect()
33}
34
35pub fn is_trusted(base: Option<&Path>, root: &Path) -> Result<bool, SessionError> {
36 let Some(path) = path(base) else {
37 return Ok(false);
38 };
39 Ok(load(&path)?
40 .iter()
41 .any(|entry| matches!(entry, FileTarget::Local(path) if path == root)))
42}
43
44pub fn trust(base: Option<&Path>, root: &Path) -> Result<(), SessionError> {
45 strop_core::path_serde::validate(root)?;
46 save(base, FileTarget::Local(root.to_owned()))
47}
48
49pub fn is_trusted_remote(
50 base: Option<&Path>,
51 endpoint: &strop_workspace::RemoteEndpoint,
52 root: &Path,
53) -> Result<bool, SessionError> {
54 let Some(path) = path(base) else {
55 return Ok(false);
56 };
57 let file = strop_workspace::RemoteFile::from_path(endpoint.clone(), root.to_owned())
58 .map_err(|error| SessionError::Invalid(error.to_string()))?;
59 let target = FileTarget::Remote(file.into());
60 Ok(load(&path)?.contains(&target))
61}
62pub fn trust_remote(
63 base: Option<&Path>,
64 root: &strop_workspace::RemoteFile,
65) -> Result<(), SessionError> {
66 save(base, FileTarget::Remote(root.clone().into()))
67}
68fn save(base: Option<&Path>, target: FileTarget) -> Result<(), SessionError> {
69 let path = path(base).ok_or_else(|| {
70 SessionError::Invalid("state directory unavailable; trust was not saved".into())
71 })?;
72 let mut entries = load(&path)?;
73 if !entries.contains(&target) {
74 entries.push(target);
75 persistence::write(&path, &entries)?;
76 }
77 Ok(())
78}