feat(plugin): cache permissions approval/decline
This commit is contained in:
parent
aad2e477d9
commit
c786bb0dc2
43
pumpkin/src/plugin/cache.rs
Normal file
43
pumpkin/src/plugin/cache.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::Path;
|
||||||
|
use tokio::fs;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct PermissionCacheEntry {
|
||||||
|
pub permissions_requested: Vec<String>,
|
||||||
|
pub approved: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||||
|
pub struct PermissionCache {
|
||||||
|
pub entries: HashMap<String, PermissionCacheEntry>, // Key is the hex hash of the plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PermissionCache {
|
||||||
|
pub async fn load(path: &Path) -> Self {
|
||||||
|
if let Ok(data) = fs::read_to_string(path).await {
|
||||||
|
serde_json::from_str(&data).unwrap_or_default()
|
||||||
|
} else {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn save(&self, path: &Path) -> tokio::io::Result<()> {
|
||||||
|
let data = serde_json::to_string_pretty(self).unwrap();
|
||||||
|
fs::write(path, data).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn calculate_hash(path: &Path) -> tokio::io::Result<String> {
|
||||||
|
let bytes = fs::read(path).await?;
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
hasher.update(&bytes);
|
||||||
|
let result = hasher.finalize();
|
||||||
|
Ok(result
|
||||||
|
.iter()
|
||||||
|
.map(|b| format!("{b:02x}"))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(""))
|
||||||
|
}
|
||||||
@ -17,6 +17,7 @@ use tokio::{
|
|||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
|
pub mod cache;
|
||||||
pub mod loader;
|
pub mod loader;
|
||||||
/// Constants for plugin permissions.
|
/// Constants for plugin permissions.
|
||||||
///
|
///
|
||||||
@ -671,6 +672,9 @@ impl PluginManager {
|
|||||||
return Ok(std::time::Duration::ZERO);
|
return Ok(std::time::Duration::ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cache_path = path.join("permission_cache.json");
|
||||||
|
let mut cache = cache::PermissionCache::load(&cache_path).await;
|
||||||
|
|
||||||
let mut prepared_plugins = Vec::new();
|
let mut prepared_plugins = Vec::new();
|
||||||
|
|
||||||
for entry in std::fs::read_dir(path)? {
|
for entry in std::fs::read_dir(path)? {
|
||||||
@ -746,7 +750,40 @@ impl PluginManager {
|
|||||||
for name in sorted_names {
|
for name in sorted_names {
|
||||||
if let Some((instance, metadata, loader_data, loader, path)) = plugins_map.remove(&name)
|
if let Some((instance, metadata, loader_data, loader, path)) = plugins_map.remove(&name)
|
||||||
{
|
{
|
||||||
let (allowed, wait_time) = Self::ask_permission_confirmation(&metadata);
|
let hash = cache::calculate_hash(&path).await.unwrap_or_default();
|
||||||
|
let allowed;
|
||||||
|
let mut wait_time = std::time::Duration::ZERO;
|
||||||
|
|
||||||
|
if let Some(entry) = cache.entries.get(&hash) {
|
||||||
|
if entry.permissions_requested == metadata.permissions {
|
||||||
|
allowed = entry.approved;
|
||||||
|
info!(
|
||||||
|
"Found cached permission decision for plugin \"{}\" (approved: {})",
|
||||||
|
metadata.name, allowed
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
(allowed, wait_time) = Self::ask_permission_confirmation(&metadata);
|
||||||
|
cache.entries.insert(
|
||||||
|
hash,
|
||||||
|
cache::PermissionCacheEntry {
|
||||||
|
permissions_requested: metadata.permissions.clone(),
|
||||||
|
approved: allowed,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let _ = cache.save(&cache_path).await;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(allowed, wait_time) = Self::ask_permission_confirmation(&metadata);
|
||||||
|
cache.entries.insert(
|
||||||
|
hash,
|
||||||
|
cache::PermissionCacheEntry {
|
||||||
|
permissions_requested: metadata.permissions.clone(),
|
||||||
|
approved: allowed,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let _ = cache.save(&cache_path).await;
|
||||||
|
}
|
||||||
|
|
||||||
total_wait_time += wait_time;
|
total_wait_time += wait_time;
|
||||||
|
|
||||||
if !allowed {
|
if !allowed {
|
||||||
@ -784,7 +821,42 @@ impl PluginManager {
|
|||||||
if loader.can_load(path) {
|
if loader.can_load(path) {
|
||||||
let (instance, metadata, loader_data) = loader.load(path).await?;
|
let (instance, metadata, loader_data) = loader.load(path).await?;
|
||||||
|
|
||||||
let (allowed, _wait_time) = Self::ask_permission_confirmation(&metadata);
|
let cache_path = Path::new(PLUGIN_DIR).join("permission_cache.json");
|
||||||
|
let mut cache = cache::PermissionCache::load(&cache_path).await;
|
||||||
|
let hash = cache::calculate_hash(path).await.unwrap_or_default();
|
||||||
|
|
||||||
|
let allowed;
|
||||||
|
|
||||||
|
if let Some(entry) = cache.entries.get(&hash) {
|
||||||
|
if entry.permissions_requested == metadata.permissions {
|
||||||
|
allowed = entry.approved;
|
||||||
|
info!(
|
||||||
|
"Found cached permission decision for plugin \"{}\" (approved: {})",
|
||||||
|
metadata.name, allowed
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
(allowed, _) = Self::ask_permission_confirmation(&metadata);
|
||||||
|
cache.entries.insert(
|
||||||
|
hash,
|
||||||
|
cache::PermissionCacheEntry {
|
||||||
|
permissions_requested: metadata.permissions.clone(),
|
||||||
|
approved: allowed,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let _ = cache.save(&cache_path).await;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(allowed, _) = Self::ask_permission_confirmation(&metadata);
|
||||||
|
cache.entries.insert(
|
||||||
|
hash,
|
||||||
|
cache::PermissionCacheEntry {
|
||||||
|
permissions_requested: metadata.permissions.clone(),
|
||||||
|
approved: allowed,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let _ = cache.save(&cache_path).await;
|
||||||
|
}
|
||||||
|
|
||||||
if !allowed {
|
if !allowed {
|
||||||
warn!(
|
warn!(
|
||||||
"Permission denied for plugin \"{}\", skipping loading.",
|
"Permission denied for plugin \"{}\", skipping loading.",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user