mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
plugin-api: Rework filesystem permissions and move data folders. (#2643)
This commit is contained in:
@@ -34,16 +34,14 @@ pub const NETWORK_OUTBOUND: &str = "network.outbound";
|
||||
/// This is separate from `network.outbound`. This allows the use of `wasi:http`; the other allows the more powerful `wasi:sockets`.
|
||||
pub const HTTP_OUTBOUND: &str = "http.outbound";
|
||||
|
||||
/// Allows the plugin to read files from the server's file system outside of its data folder.
|
||||
pub const FS_READ: &str = "fs.read";
|
||||
|
||||
/// Allows the plugin to write files to the server's file system outside of its data folder.
|
||||
pub const FS_WRITE: &str = "fs.write";
|
||||
|
||||
/// Allows the plugin to read files within its own data folder (`plugins/<name>`).
|
||||
/// Allows the plugin to read files within its own data folder (`plugins/data/<name>`).
|
||||
pub const FS_READ_DATA: &str = "fs.read.data";
|
||||
|
||||
/// Allows the plugin to write files within its own data folder (`plugins/<name>`).
|
||||
/// Allows the plugin to write files within its own data folder (`plugins/data/<name>`).
|
||||
///
|
||||
/// Note that even without `FS_READ_DATA`, this will allow the plugin to
|
||||
/// inspect (e.g. list) the contents of the directory. But it will block
|
||||
/// reading any file's contents.
|
||||
pub const FS_WRITE_DATA: &str = "fs.write.data";
|
||||
|
||||
/// Allows the plugin to read all environment variables.
|
||||
|
||||
@@ -80,7 +80,7 @@ impl Context {
|
||||
/// A string representing the path to the data folder.
|
||||
#[must_use]
|
||||
pub fn get_data_folder(&self) -> PathBuf {
|
||||
let path = Path::new("plugins").join(&self.metadata.name);
|
||||
let path = Path::new("plugins").join("data").join(&self.metadata.name);
|
||||
if !path.exists() {
|
||||
fs::create_dir_all(&path).unwrap();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::{fs, path::Path, sync::Arc};
|
||||
use thiserror::Error;
|
||||
use tokio::sync::Mutex;
|
||||
use wasmtime::{Cache, CacheConfig, Engine, Store, component::Component, component::Linker};
|
||||
use wasmtime_wasi::{WasiCtxBuilder, sockets::SocketAddrUse};
|
||||
use wasmtime_wasi::{DirPerms, FilePerms, WasiCtxBuilder, sockets::SocketAddrUse};
|
||||
|
||||
use crate::plugin::{
|
||||
Context, PluginMetadata, loader::wasm::wasm_host::state::PluginHostState, permissions,
|
||||
@@ -143,7 +143,6 @@ fn load_component(
|
||||
}
|
||||
|
||||
impl WasmPlugin {
|
||||
#[expect(clippy::too_many_lines)]
|
||||
pub async fn on_load(
|
||||
&self,
|
||||
context: Arc<Context>,
|
||||
@@ -221,48 +220,29 @@ impl WasmPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
let data_folder = context.get_data_folder();
|
||||
let preopen_path =
|
||||
if has_permission(permissions::FS_READ) || has_permission(permissions::FS_WRITE) {
|
||||
Path::new(".")
|
||||
} else {
|
||||
data_folder.as_path()
|
||||
};
|
||||
|
||||
// Determine permissions for the preopened directory
|
||||
let (dir_perms, file_perms) = if has_permission(permissions::FS_WRITE) {
|
||||
(
|
||||
wasmtime_wasi::DirPerms::all(),
|
||||
wasmtime_wasi::FilePerms::all(),
|
||||
)
|
||||
} else if has_permission(permissions::FS_READ) {
|
||||
(
|
||||
wasmtime_wasi::DirPerms::READ,
|
||||
wasmtime_wasi::FilePerms::READ,
|
||||
)
|
||||
} else {
|
||||
// Scoped to data folder
|
||||
let can_write = has_permission(permissions::FS_WRITE_DATA);
|
||||
if can_write {
|
||||
(
|
||||
wasmtime_wasi::DirPerms::all(),
|
||||
wasmtime_wasi::FilePerms::all(),
|
||||
)
|
||||
} else {
|
||||
// Default to READ if no write permission is given for data folder
|
||||
// (Plugins should at least be able to read their own config)
|
||||
(
|
||||
wasmtime_wasi::DirPerms::READ,
|
||||
wasmtime_wasi::FilePerms::READ,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
builder.preopened_dir(
|
||||
preopen_path,
|
||||
preopen_path.to_string_lossy(),
|
||||
dir_perms,
|
||||
file_perms,
|
||||
context.get_data_folder(),
|
||||
"data",
|
||||
if has_permission(permissions::FS_READ_DATA)
|
||||
|| has_permission(permissions::FS_WRITE_DATA)
|
||||
{
|
||||
DirPerms::READ
|
||||
} else {
|
||||
DirPerms::empty()
|
||||
} | if has_permission(permissions::FS_WRITE_DATA) {
|
||||
DirPerms::MUTATE
|
||||
} else {
|
||||
DirPerms::empty()
|
||||
},
|
||||
if has_permission(permissions::FS_READ_DATA) {
|
||||
FilePerms::READ
|
||||
} else {
|
||||
FilePerms::empty()
|
||||
} | if has_permission(permissions::FS_WRITE_DATA) {
|
||||
FilePerms::WRITE
|
||||
} else {
|
||||
FilePerms::empty()
|
||||
},
|
||||
)?;
|
||||
|
||||
if has_permission(permissions::HTTP_OUTBOUND) {
|
||||
|
||||
@@ -419,13 +419,8 @@ impl pumpkin::plugin::context::HostContext for PluginHostState {
|
||||
.await)
|
||||
}
|
||||
|
||||
async fn get_data_folder(&mut self, context: Resource<Context>) -> wasmtime::Result<String> {
|
||||
Ok(self
|
||||
.get_context(&context)?
|
||||
.provider
|
||||
.get_data_folder()
|
||||
.to_string_lossy()
|
||||
.into_owned())
|
||||
async fn get_data_folder(&mut self, _context: Resource<Context>) -> wasmtime::Result<String> {
|
||||
Ok("data".to_string())
|
||||
}
|
||||
|
||||
async fn get_server(
|
||||
|
||||
@@ -486,15 +486,13 @@ impl PluginManager {
|
||||
metadata.version.green()
|
||||
);
|
||||
for permission in &metadata.permissions {
|
||||
if let Some(description) = permissions::get_permission_description(permission) {
|
||||
println!(
|
||||
" - {}: {}",
|
||||
permission.yellow().bold(),
|
||||
description.italic()
|
||||
);
|
||||
} else {
|
||||
println!(" - {}", permission.yellow().bold());
|
||||
}
|
||||
println!(
|
||||
" - {}: {}",
|
||||
permission.yellow().bold(),
|
||||
permissions::get_permission_description(permission)
|
||||
.unwrap_or("<unknown permission>")
|
||||
.italic()
|
||||
);
|
||||
}
|
||||
|
||||
let prompt = format!(
|
||||
|
||||
@@ -38,17 +38,14 @@ pub const NETWORK_OUTBOUND: &str = "network.outbound";
|
||||
/// This is separate from `network.outbound`. This allows the use of `wasi:http`; the other allows the more powerful `wasi:sockets`.
|
||||
pub const HTTP_OUTBOUND: &str = "http.outbound";
|
||||
|
||||
/// Allows the plugin to read files from the server's file system outside of its data folder.
|
||||
pub const FS_READ: &str = "fs.read";
|
||||
|
||||
/// Allows the plugin to write files to the server's file system outside of its data folder.
|
||||
pub const FS_WRITE: &str = "fs.write";
|
||||
|
||||
/// Allows the plugin to read files within its own data folder (`plugins/<name>`).
|
||||
/// This is granted by default if any other FS permission is not specified, but can be explicitly requested.
|
||||
/// Allows the plugin to read files within its own data folder (`plugins/data/<name>`).
|
||||
pub const FS_READ_DATA: &str = "fs.read.data";
|
||||
|
||||
/// Allows the plugin to write files within its own data folder (`plugins/<name>`).
|
||||
/// Allows the plugin to write files within its own data folder (`plugins/data/<name>`).
|
||||
///
|
||||
/// Note that even without `FS_READ_DATA`, this will allow the plugin to
|
||||
/// inspect (e.g. list) the contents of the directory. But it will block
|
||||
/// reading any file's contents.
|
||||
pub const FS_WRITE_DATA: &str = "fs.write.data";
|
||||
|
||||
/// Allows the plugin to read all environment variables.
|
||||
@@ -98,14 +95,13 @@ pub fn get_permission_description(permission: &str) -> Option<&'static str> {
|
||||
HTTP_OUTBOUND => {
|
||||
Some("Allows the plugin to make outbound HTTP requests (through `wasi:http`)")
|
||||
}
|
||||
FS_READ => Some(
|
||||
"Allows the plugin to read files from the server's file system outside of its data folder.",
|
||||
),
|
||||
FS_WRITE => Some(
|
||||
"Allows the plugin to write files to the server's file system outside of its data folder.",
|
||||
),
|
||||
FS_READ_DATA => Some("Allows the plugin to read files within its own data folder."),
|
||||
FS_WRITE_DATA => Some("Allows the plugin to write files within its own data folder."),
|
||||
FS_WRITE_DATA => Some(
|
||||
"\
|
||||
Allows the plugin to write files within its own data folder. \
|
||||
Even without `fs.read.data`, this will allow the plugin to list directory contents \
|
||||
(but not read the contents of the discovered files).",
|
||||
),
|
||||
SYS_ENV => Some("Allows the plugin to read all environment variables."),
|
||||
SYS_INFO => Some("Allows the plugin to read system information (CPU, Memory, OS)."),
|
||||
SYS_INFO_CPU => Some("Allows the plugin to read CPU information."),
|
||||
|
||||
Reference in New Issue
Block a user