mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
feat: plugin permission system
This commit is contained in:
@@ -88,6 +88,7 @@ pub fn plugin_impl(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
authors: env!("CARGO_PKG_AUTHORS").split(',').map(String::from).collect(),
|
||||
description: env!("CARGO_PKG_DESCRIPTION").to_string(),
|
||||
dependencies: Vec::new(),
|
||||
permissions: Vec::new(),
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ use tracing::{debug, warn};
|
||||
pub mod fun;
|
||||
pub mod logging;
|
||||
pub mod networking;
|
||||
pub mod plugins;
|
||||
pub mod recipe;
|
||||
|
||||
pub mod resource_pack;
|
||||
@@ -22,6 +23,7 @@ pub use networking::auth::AuthenticationConfig;
|
||||
pub use networking::compression::CompressionConfig;
|
||||
pub use networking::lan_broadcast::LANBroadcastConfig;
|
||||
pub use networking::rcon::RCONConfig;
|
||||
pub use plugins::PluginsConfig;
|
||||
pub use pvp::PVPConfig;
|
||||
pub use server_links::ServerLinksConfig;
|
||||
|
||||
@@ -74,6 +76,8 @@ pub struct AdvancedConfiguration {
|
||||
pub fun: FunConfig,
|
||||
/// Recipe-related configuration.
|
||||
pub recipe: RecipeConfig,
|
||||
/// Plugin-related configuration.
|
||||
pub plugins: PluginsConfig,
|
||||
}
|
||||
|
||||
/// Basic configuration for core server settings.
|
||||
|
||||
8
pumpkin-config/src/plugins.rs
Normal file
8
pumpkin-config/src/plugins.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize, Default)]
|
||||
#[serde(default)]
|
||||
pub struct PluginsConfig {
|
||||
/// List of permissions that are globally blocked for all plugins.
|
||||
pub blocked_permissions: Vec<String>,
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
//! # Quick start
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! use pumpkin_plugin_api::{Plugin, PluginMetadata, Context, register_plugin};
|
||||
//! use pumpkin_plugin_api::{Plugin, PluginMetadata, Context, register_plugin, permissions::permissions};
|
||||
//!
|
||||
//! struct MyPlugin;
|
||||
//!
|
||||
@@ -20,6 +20,7 @@
|
||||
//! authors: vec!["you".into()],
|
||||
//! description: "An example plugin.".into(),
|
||||
//! dependencies: vec![],
|
||||
//! permissions: vec![permissions::NETWORK_DNS.into()],
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
@@ -34,6 +35,10 @@ use crate::{
|
||||
|
||||
pub mod commands;
|
||||
pub mod events;
|
||||
/// Constants for plugin permissions.
|
||||
///
|
||||
/// Use these in your `PluginMetadata` to request access to specific host features.
|
||||
pub mod permissions;
|
||||
pub mod scheduler;
|
||||
|
||||
pub mod command {
|
||||
@@ -77,6 +82,8 @@ pub struct PluginMetadata {
|
||||
pub description: String,
|
||||
/// The list of plugin dependencies.
|
||||
pub dependencies: Vec<String>,
|
||||
/// The list of permissions requested by the plugin.
|
||||
pub permissions: Vec<String>,
|
||||
}
|
||||
|
||||
impl wit::exports::pumpkin::plugin::metadata::Guest for Component {
|
||||
@@ -89,6 +96,7 @@ impl wit::exports::pumpkin::plugin::metadata::Guest for Component {
|
||||
authors: metadata.authors,
|
||||
description: metadata.description,
|
||||
dependencies: metadata.dependencies,
|
||||
permissions: metadata.permissions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
65
pumpkin-plugin-api/src/permissions.rs
Normal file
65
pumpkin-plugin-api/src/permissions.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
/// Constants for plugin permissions.
|
||||
///
|
||||
/// Use these in your `PluginMetadata` to request access to specific host features.
|
||||
|
||||
/// Allows the plugin to perform DNS resolution.
|
||||
pub const NETWORK_DNS: &str = "network.dns";
|
||||
|
||||
/// Allows the plugin to use TCP sockets.
|
||||
pub const NETWORK_TCP: &str = "network.tcp";
|
||||
|
||||
/// Allows the plugin to use UDP sockets.
|
||||
pub const NETWORK_UDP: &str = "network.udp";
|
||||
|
||||
/// Allows the plugin to initiate TCP connections.
|
||||
pub const NETWORK_TCP_CONNECT: &str = "network.tcp.connect";
|
||||
|
||||
/// Allows the plugin to bind TCP listeners (accept inbound connections).
|
||||
pub const NETWORK_TCP_BIND: &str = "network.tcp.bind";
|
||||
|
||||
/// Allows the plugin to send and receive UDP packets to specific destinations.
|
||||
pub const NETWORK_UDP_CONNECT: &str = "network.udp.connect";
|
||||
|
||||
/// Allows the plugin to bind UDP sockets to local ports.
|
||||
pub const NETWORK_UDP_BIND: &str = "network.udp.bind";
|
||||
|
||||
/// Allows the plugin to send datagram on non-connected UDP socket.
|
||||
pub const NETWORK_UDP_OUTGOING_DATAGRAM: &str = "network.udp.outgoingdatagram";
|
||||
|
||||
/// Restricts all networking permissions to loopback addresses (localhost) only.
|
||||
pub const NETWORK_LOOPBACK: &str = "network.loopback";
|
||||
|
||||
/// Allows the plugin to make outbound TCP/UDP connections.
|
||||
/// **Warning:** This is a powerful permission.
|
||||
pub const NETWORK_OUTBOUND: &str = "network.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>`).
|
||||
pub const FS_READ_DATA: &str = "fs.read.data";
|
||||
|
||||
/// Allows the plugin to write files within its own data folder (`plugins/<name>`).
|
||||
pub const FS_WRITE_DATA: &str = "fs.write.data";
|
||||
|
||||
/// Allows the plugin to read all environment variables.
|
||||
pub const SYS_ENV: &str = "sys.env";
|
||||
|
||||
/// Allows the plugin to read specific environment variables.
|
||||
/// Used with a prefix like "sys.env.PATH".
|
||||
pub const SYS_ENV_PREFIX: &str = "sys.env.";
|
||||
|
||||
/// Allows the plugin to read system information (CPU, Memory, OS).
|
||||
pub const SYS_INFO: &str = "sys.info";
|
||||
|
||||
/// Allows the plugin to read CPU information.
|
||||
pub const SYS_INFO_CPU: &str = "sys.info.cpu";
|
||||
|
||||
/// Allows the plugin to read RAM information.
|
||||
pub const SYS_INFO_RAM: &str = "sys.info.ram";
|
||||
|
||||
/// Allows the plugin to read OS information.
|
||||
pub const SYS_INFO_OS: &str = "sys.info.os";
|
||||
@@ -11,6 +11,8 @@ interface metadata {
|
||||
description: string,
|
||||
/// Plugin dependencies.
|
||||
dependencies: list<string>,
|
||||
/// Permissions requested by the plugin.
|
||||
permissions: list<string>,
|
||||
}
|
||||
|
||||
get-metadata: func() -> plugin-metadata;
|
||||
|
||||
@@ -23,6 +23,15 @@ interface server {
|
||||
end,
|
||||
}
|
||||
|
||||
record sys-info {
|
||||
cpu-count: option<u32>,
|
||||
total-memory: option<u64>,
|
||||
used-memory: option<u64>,
|
||||
os-name: option<string>,
|
||||
os-version: option<string>,
|
||||
pumpkin-version: string,
|
||||
}
|
||||
|
||||
variant command-sender {
|
||||
console,
|
||||
player(player),
|
||||
@@ -30,6 +39,10 @@ interface server {
|
||||
|
||||
/// Represents the global server instance.
|
||||
resource server {
|
||||
/// Returns system information (CPU, Memory, OS).
|
||||
/// Fields are returned only if the plugin has the corresponding permissions.
|
||||
get-sys-info: func() -> sys-info;
|
||||
|
||||
/// Returns the current difficulty level of the server.
|
||||
get-difficulty: func() -> difficulty;
|
||||
|
||||
|
||||
@@ -66,6 +66,11 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn get_metadata(&self) -> &PluginMetadata {
|
||||
&self.metadata
|
||||
}
|
||||
|
||||
/// Retrieves the data folder path for the plugin, creating it if it does not exist.
|
||||
///
|
||||
/// # Returns
|
||||
|
||||
@@ -24,6 +24,8 @@ pub struct PluginMetadata {
|
||||
pub description: String,
|
||||
/// The dependencies of the plugin.
|
||||
pub dependencies: Vec<String>,
|
||||
/// The permissions requested by the plugin.
|
||||
pub permissions: Vec<String>,
|
||||
}
|
||||
|
||||
/// This type represents a future for the plugin.
|
||||
|
||||
@@ -2,9 +2,11 @@ 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;
|
||||
use wasmtime_wasi::{WasiCtxBuilder, sockets::SocketAddrUse};
|
||||
|
||||
use crate::plugin::{Context, PluginMetadata, loader::wasm::wasm_host::state::PluginHostState};
|
||||
use crate::plugin::{
|
||||
Context, PluginMetadata, loader::wasm::wasm_host::state::PluginHostState, permissions,
|
||||
};
|
||||
|
||||
pub mod args;
|
||||
pub mod logging;
|
||||
@@ -144,13 +146,117 @@ impl WasmPlugin {
|
||||
|
||||
let mut builder = WasiCtxBuilder::new();
|
||||
|
||||
let metadata = context.get_metadata();
|
||||
let blocked_permissions = &context.server.advanced_config.plugins.blocked_permissions;
|
||||
|
||||
let filtered_permissions: Vec<String> = metadata
|
||||
.permissions
|
||||
.iter()
|
||||
.filter(|p| !blocked_permissions.iter().any(|blocked| blocked == *p))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let has_permission = |p: &str| filtered_permissions.iter().any(|perm| perm == p);
|
||||
|
||||
if has_permission(permissions::NETWORK_DNS) {
|
||||
builder.allow_ip_name_lookup(true);
|
||||
}
|
||||
|
||||
let tcp_allowed = has_permission(permissions::NETWORK_TCP);
|
||||
let udp_allowed = has_permission(permissions::NETWORK_UDP);
|
||||
let tcp_connect = tcp_allowed || has_permission(permissions::NETWORK_TCP_CONNECT);
|
||||
let tcp_bind = tcp_allowed || has_permission(permissions::NETWORK_TCP_BIND);
|
||||
let udp_connect = udp_allowed || has_permission(permissions::NETWORK_UDP_CONNECT);
|
||||
let udp_bind = udp_allowed || has_permission(permissions::NETWORK_UDP_BIND);
|
||||
let udp_outgoing_datagram =
|
||||
udp_allowed || has_permission(permissions::NETWORK_UDP_OUTGOING_DATAGRAM);
|
||||
|
||||
let loopback_only = has_permission(permissions::NETWORK_LOOPBACK);
|
||||
|
||||
builder.allow_tcp(tcp_connect || tcp_bind);
|
||||
builder.allow_udp(udp_connect || udp_bind);
|
||||
|
||||
builder.socket_addr_check(move |addr, reason| {
|
||||
Box::pin(async move {
|
||||
let ok = match reason {
|
||||
SocketAddrUse::TcpConnect => tcp_connect,
|
||||
SocketAddrUse::TcpBind => tcp_bind,
|
||||
SocketAddrUse::UdpConnect => udp_connect,
|
||||
SocketAddrUse::UdpBind => udp_bind,
|
||||
SocketAddrUse::UdpOutgoingDatagram => udp_outgoing_datagram,
|
||||
};
|
||||
|
||||
if loopback_only {
|
||||
ok && addr.ip().is_loopback()
|
||||
} else {
|
||||
ok
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if has_permission(permissions::NETWORK_OUTBOUND) {
|
||||
builder.inherit_network();
|
||||
}
|
||||
|
||||
// --- System Permissions ---
|
||||
|
||||
// Environment Variables
|
||||
if has_permission(permissions::SYS_ENV) {
|
||||
builder.inherit_env();
|
||||
} else {
|
||||
for (key, value) in std::env::vars() {
|
||||
let perm = format!("{}{}", permissions::SYS_ENV_PREFIX, key);
|
||||
if has_permission(&perm) {
|
||||
builder.env(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
context.get_data_folder(),
|
||||
context.get_data_folder().to_string_lossy(),
|
||||
wasmtime_wasi::DirPerms::all(),
|
||||
wasmtime_wasi::FilePerms::all(),
|
||||
preopen_path,
|
||||
preopen_path.to_string_lossy(),
|
||||
dir_perms,
|
||||
file_perms,
|
||||
)?;
|
||||
|
||||
store.data_mut().permissions = filtered_permissions;
|
||||
store.data_mut().wasi_ctx = builder.build();
|
||||
|
||||
store.data_mut().server = Some(context.server.clone());
|
||||
|
||||
@@ -52,6 +52,7 @@ pub struct PluginHostState {
|
||||
pub resource_table: ResourceTable,
|
||||
pub plugin: Option<Weak<WasmPlugin>>,
|
||||
pub server: Option<Arc<Server>>,
|
||||
pub permissions: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for PluginHostState {
|
||||
@@ -69,6 +70,7 @@ impl PluginHostState {
|
||||
resource_table,
|
||||
plugin: None,
|
||||
server: None,
|
||||
permissions: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,8 +62,11 @@ pub async fn init_plugin(
|
||||
authors: metadata.authors,
|
||||
description: metadata.description,
|
||||
dependencies: metadata.dependencies,
|
||||
permissions: metadata.permissions.clone(),
|
||||
};
|
||||
|
||||
store.data_mut().permissions = metadata.permissions.clone();
|
||||
|
||||
Ok((
|
||||
WasmPlugin {
|
||||
plugin_instance: PluginInstance::V0_1(plugin),
|
||||
|
||||
@@ -6,15 +6,18 @@ use crate::command::CommandSender;
|
||||
use pumpkin::plugin::server::CommandSender as WasmCommandSender;
|
||||
|
||||
use super::player::text_component_from_resource;
|
||||
use crate::plugin::loader::wasm::wasm_host::{
|
||||
state::{PluginHostState, ServerResource},
|
||||
wit::v0_1::pumpkin::{
|
||||
self,
|
||||
plugin::{
|
||||
player::Player,
|
||||
server::{Difficulty, Dimension, Server},
|
||||
use crate::plugin::{
|
||||
loader::wasm::wasm_host::{
|
||||
state::{PluginHostState, ServerResource},
|
||||
wit::v0_1::pumpkin::{
|
||||
self,
|
||||
plugin::{
|
||||
player::Player,
|
||||
server::{Difficulty, Dimension, Server, SysInfo},
|
||||
},
|
||||
},
|
||||
},
|
||||
permissions,
|
||||
};
|
||||
|
||||
impl PluginHostState {
|
||||
@@ -28,6 +31,42 @@ impl PluginHostState {
|
||||
impl pumpkin::plugin::server::Host for PluginHostState {}
|
||||
|
||||
impl pumpkin::plugin::server::HostServer for PluginHostState {
|
||||
async fn get_sys_info(&mut self, _res: Resource<Server>) -> wasmtime::Result<SysInfo> {
|
||||
let has_perm = |p: &str| self.permissions.iter().any(|perm| perm == p);
|
||||
|
||||
let mut sys = sysinfo::System::new_all();
|
||||
sys.refresh_all();
|
||||
|
||||
let cpu_count = if has_perm(permissions::SYS_INFO) || has_perm(permissions::SYS_INFO_CPU) {
|
||||
Some(sys.cpus().len() as u32)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (total_memory, used_memory) =
|
||||
if has_perm(permissions::SYS_INFO) || has_perm(permissions::SYS_INFO_RAM) {
|
||||
(Some(sys.total_memory()), Some(sys.used_memory()))
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
let (os_name, os_version) =
|
||||
if has_perm(permissions::SYS_INFO) || has_perm(permissions::SYS_INFO_OS) {
|
||||
(sysinfo::System::name(), sysinfo::System::os_version())
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
Ok(SysInfo {
|
||||
cpu_count,
|
||||
total_memory,
|
||||
used_memory,
|
||||
os_name,
|
||||
os_version,
|
||||
pumpkin_version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_difficulty(&mut self, res: Resource<Server>) -> wasmtime::Result<Difficulty> {
|
||||
let resource = self.get_server_res(&res)?;
|
||||
|
||||
|
||||
@@ -14,10 +14,15 @@ use tokio::{
|
||||
sync::{Notify, RwLock},
|
||||
task::JoinHandle,
|
||||
};
|
||||
use tracing::{debug, error, info};
|
||||
use tracing::{debug, error, info, warn};
|
||||
|
||||
pub mod api;
|
||||
pub mod loader;
|
||||
/// Constants for plugin permissions.
|
||||
///
|
||||
/// Plugins can request these permissions in their metadata to access specific
|
||||
/// host features.
|
||||
pub mod permissions;
|
||||
|
||||
use crate::{LOGGER_IMPL, plugin::loader::wasm::WasmPluginLoader, server::Server};
|
||||
pub use api::*;
|
||||
@@ -462,6 +467,7 @@ impl PluginManager {
|
||||
}
|
||||
|
||||
/// Spawn initialization for a single plugin
|
||||
#[expect(clippy::too_many_lines)]
|
||||
async fn spawn_plugin_initialization(
|
||||
&self,
|
||||
mut instance: Box<dyn Plugin>,
|
||||
@@ -541,6 +547,13 @@ impl PluginManager {
|
||||
state_notify.notify_waiters();
|
||||
|
||||
info!("Loaded {} ({})", metadata.name, metadata.version);
|
||||
|
||||
if !metadata.permissions.is_empty() {
|
||||
warn!(
|
||||
"Plugin \"{}\" uses the following permissions: {:?}",
|
||||
metadata.name, metadata.permissions
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
// Handle initialization failure
|
||||
|
||||
71
pumpkin/src/plugin/permissions.rs
Normal file
71
pumpkin/src/plugin/permissions.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
/// Constants for plugin permissions.
|
||||
///
|
||||
/// Plugins can request these permissions in their metadata to access specific
|
||||
/// host features.
|
||||
|
||||
/// Allows the plugin to perform DNS resolution (resolving hostnames to IP addresses).
|
||||
///
|
||||
/// Corresponds to the `wasi:sockets/ip-name-lookup` interface.
|
||||
pub const NETWORK_DNS: &str = "network.dns";
|
||||
|
||||
/// Allows the plugin to use TCP sockets.
|
||||
pub const NETWORK_TCP: &str = "network.tcp";
|
||||
|
||||
/// Allows the plugin to use UDP sockets.
|
||||
pub const NETWORK_UDP: &str = "network.udp";
|
||||
|
||||
/// Allows the plugin to initiate TCP connections.
|
||||
pub const NETWORK_TCP_CONNECT: &str = "network.tcp.connect";
|
||||
|
||||
/// Allows the plugin to bind TCP listeners (accept inbound connections).
|
||||
pub const NETWORK_TCP_BIND: &str = "network.tcp.bind";
|
||||
|
||||
/// Allows the plugin to send and receive UDP packets to specific destinations.
|
||||
pub const NETWORK_UDP_CONNECT: &str = "network.udp.connect";
|
||||
|
||||
/// Allows the plugin to bind UDP sockets to local ports.
|
||||
pub const NETWORK_UDP_BIND: &str = "network.udp.bind";
|
||||
|
||||
/// Allows the plugin to send datagram on non-connected UDP socket.
|
||||
pub const NETWORK_UDP_OUTGOING_DATAGRAM: &str = "network.udp.outgoingdatagram";
|
||||
|
||||
/// Restricts all networking permissions to loopback addresses (localhost) only.
|
||||
pub const NETWORK_LOOPBACK: &str = "network.loopback";
|
||||
|
||||
/// Allows the plugin to make outbound TCP/UDP connections.
|
||||
///
|
||||
/// This gives the plugin full access to the host's network interfaces.
|
||||
/// **Warning:** This is a powerful permission and should only be granted to trusted plugins.
|
||||
pub const NETWORK_OUTBOUND: &str = "network.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.
|
||||
pub const FS_READ_DATA: &str = "fs.read.data";
|
||||
|
||||
/// Allows the plugin to write files within its own data folder (`plugins/<name>`).
|
||||
pub const FS_WRITE_DATA: &str = "fs.write.data";
|
||||
|
||||
/// Allows the plugin to read all environment variables.
|
||||
pub const SYS_ENV: &str = "sys.env";
|
||||
|
||||
/// Allows the plugin to read specific environment variables.
|
||||
/// Used with a prefix like "sys.env.PATH".
|
||||
pub const SYS_ENV_PREFIX: &str = "sys.env.";
|
||||
|
||||
/// Allows the plugin to read system information (CPU, Memory, OS).
|
||||
pub const SYS_INFO: &str = "sys.info";
|
||||
|
||||
/// Allows the plugin to read CPU information.
|
||||
pub const SYS_INFO_CPU: &str = "sys.info.cpu";
|
||||
|
||||
/// Allows the plugin to read RAM information.
|
||||
pub const SYS_INFO_RAM: &str = "sys.info.ram";
|
||||
|
||||
/// Allows the plugin to read OS information.
|
||||
pub const SYS_INFO_OS: &str = "sys.info.os";
|
||||
Reference in New Issue
Block a user