Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-loader/src/workspace_trust.rs')
-rw-r--r--helix-loader/src/workspace_trust.rs188
1 files changed, 188 insertions, 0 deletions
diff --git a/helix-loader/src/workspace_trust.rs b/helix-loader/src/workspace_trust.rs
new file mode 100644
index 00000000..40bc198a
--- /dev/null
+++ b/helix-loader/src/workspace_trust.rs
@@ -0,0 +1,188 @@
+use std::{collections::HashSet, fs, path::PathBuf};
+
+use crate::{data_dir, workspace_exclude_file, workspace_trust_file};
+
+pub struct WorkspaceTrust {
+ trusted: HashSet<PathBuf>,
+ excluded: Option<HashSet<PathBuf>>,
+}
+
+#[derive(Clone, Copy)]
+pub enum TrustStatus {
+ Untrusted,
+ Trusted,
+}
+
+impl WorkspaceTrust {
+ /// Loads `WorkspaceTrust`.
+ ///
+ /// Should be used only when there is a need to change trust status
+ /// of a particular workspace.
+ ///
+ /// For querying trust status of a workspace use `quick_query_workspace()` or
+ /// `quick_query_workspace_with_explicit_untrust()`
+ pub fn load(with_exclusion: bool) -> Self {
+ let mut trusted = HashSet::new();
+
+ match fs::read_to_string(workspace_trust_file()) {
+ Ok(workspace_trust_file) => {
+ for line in workspace_trust_file.split('\n') {
+ if !line.is_empty() {
+ let path = PathBuf::from(line);
+ trusted.insert(path);
+ }
+ }
+ }
+ Err(e) => log::error!("workspace file couldn't be read: {:?}", e),
+ };
+
+ let excluded = if with_exclusion {
+ let mut untrusted = HashSet::new();
+
+ match fs::read_to_string(workspace_exclude_file()) {
+ Ok(workspace_untrust_file) => {
+ for line in workspace_untrust_file.split('\n') {
+ if !line.is_empty() {
+ let path = PathBuf::from(line);
+ untrusted.insert(path);
+ }
+ }
+ }
+ Err(e) => log::error!("workspace file couldn't be read: {:?}", e),
+ };
+
+ Some(untrusted)
+ } else {
+ None
+ };
+ WorkspaceTrust { trusted, excluded }
+ }
+
+ fn write_trust_to_file(&self) {
+ let mut trust_text = String::new();
+ for workspace in self.trusted.iter() {
+ if let Some(path_str) = workspace.to_str() {
+ trust_text += &format!("{path_str}\n");
+ }
+ }
+ // let chains aren't supported in current MSRV
+ if let Ok(false) = fs::exists(data_dir()) {
+ if let Err(e) = fs::create_dir_all(data_dir()) {
+ log::error!("Couldn't create helix's data directory: {:?}", e);
+ };
+ }
+ if let Err(e) = fs::write(workspace_trust_file(), trust_text) {
+ log::error!("Error during write of workspace_trust file: {:?}", e);
+ }
+ }
+
+ fn write_exclusion_to_file(&self) {
+ if let Some(untrusted) = &self.excluded {
+ let mut trust_text = String::new();
+ for workspace in untrusted.iter() {
+ if let Some(path_str) = workspace.to_str() {
+ trust_text += &format!("{path_str}\n");
+ }
+ }
+ // let chains aren't supported in current MSRV
+ if let Ok(false) = fs::exists(data_dir()) {
+ if let Err(e) = fs::create_dir_all(data_dir()) {
+ log::error!("Couldn't create helix's data directory: {:?}", e);
+ };
+ }
+ if let Err(e) = fs::write(workspace_exclude_file(), trust_text) {
+ log::error!("Error during write of workspace_trust file: {:?}", e);
+ }
+ } else {
+ log::error!("Called write_untrust_to_file() when self.untrusted is None");
+ }
+ }
+
+ /// Mark current workspace trusted
+ pub fn trust_workspace(&mut self) {
+ let workspace = crate::find_workspace().0;
+ self.trusted.insert(workspace);
+ self.write_trust_to_file();
+ }
+
+ /// Remove trusted mark from current workspace
+ pub fn untrust_workspace(&mut self) {
+ let workspace = crate::find_workspace().0;
+ self.trusted.remove(&workspace);
+ self.write_trust_to_file();
+ }
+
+ /// Mark current workspace excluded.
+ ///
+ /// Should be called only if `WorkspaceTrust` was created with `WorkspaceTrust::load(true)`
+ pub fn exclude_workspace(&mut self) {
+ let workspace = crate::find_workspace().0;
+ self.trusted.remove(&workspace);
+ if let Some(excluded) = &mut self.excluded {
+ excluded.insert(workspace);
+ self.write_exclusion_to_file();
+ } else {
+ log::error!("Called untrust_workspace_permanent() when self.untrusted is None");
+ }
+ }
+}
+
+#[derive(Default, Clone, Copy, Debug)]
+pub enum TrustUntrustStatus {
+ DenyAlways,
+ #[default]
+ DenyOnce,
+ AllowAlways,
+}
+
+pub fn quick_query_workspace(insecure: bool) -> TrustStatus {
+ if insecure {
+ return TrustStatus::Trusted;
+ }
+
+ let workspace = crate::find_workspace().0;
+ match fs::read_to_string(workspace_trust_file()) {
+ Ok(workspace_trust_file) => {
+ for line in workspace_trust_file.split('\n') {
+ if PathBuf::from(line) == workspace {
+ return TrustStatus::Trusted;
+ }
+ }
+ }
+ Err(err) if err.kind() == std::io::ErrorKind::NotFound => (),
+ Err(err) => log::error!("workspace file couldn't be read: {err:?}"),
+ };
+ TrustStatus::Untrusted
+}
+
+pub fn quick_query_workspace_with_explicit_untrust(insecure: bool) -> TrustUntrustStatus {
+ if insecure {
+ return TrustUntrustStatus::AllowAlways;
+ }
+
+ let workspace = crate::find_workspace().0;
+ match fs::read_to_string(workspace_trust_file()) {
+ Ok(workspace_trust_file) => {
+ for line in workspace_trust_file.split('\n') {
+ if PathBuf::from(line) == workspace {
+ return TrustUntrustStatus::AllowAlways;
+ }
+ }
+ }
+ Err(err) if err.kind() == std::io::ErrorKind::NotFound => (),
+ Err(err) => log::error!("workspace_trust file couldn't be read: {err:?}"),
+ };
+
+ match fs::read_to_string(workspace_exclude_file()) {
+ Ok(workspace_untrust_file) => {
+ for line in workspace_untrust_file.split('\n') {
+ if PathBuf::from(line) == workspace {
+ return TrustUntrustStatus::DenyAlways;
+ }
+ }
+ }
+ Err(err) if err.kind() == std::io::ErrorKind::NotFound => (),
+ Err(err) => log::error!("workspace_untrust file couldn't be read: {err:?}"),
+ };
+ TrustUntrustStatus::DenyOnce
+}