Delete src/plugins/bad-sandbox.rs

This commit is contained in:
Григорий Сафронов 2026-01-18 21:55:05 +00:00
parent c5ec1d432b
commit fafa454c24

View File

@ -1,311 +0,0 @@
//! Песочница Lua для безопасного выполнения плагинов
use std::path::Path;
use mlua::{Lua, Value as LuaValue, Result as LuaResult, Error as LuaError};
use serde_json::{Value, json};
use uuid::Uuid;
use crate::plugins::traits::{PluginEvent, PluginHook, PluginState};
use crate::plugins::channel::PluginInfo;
/// Песочница Lua для изоляции плагинов
pub struct LuaSandbox {
lua: Lua,
plugin_id: String,
hooks: Vec<PluginHook>,
}
impl LuaSandbox {
/// Создать новую песочницу
pub fn new() -> Result<Self, String> {
let lua = Lua::new();
// Настройка безопасного окружения
let globals = lua.globals();
// Ограничиваем доступ к опасным функциям
globals.set("os", LuaValue::Nil)
.map_err(|e| format!("Failed to restrict os: {}", e))?;
globals.set("io", LuaValue::Nil)
.map_err(|e| format!("Failed to restrict io: {}", e))?;
globals.set("debug", LuaValue::Nil)
.map_err(|e| format!("Failed to restrict debug: {}", e))?;
globals.set("load", LuaValue::Nil)
.map_err(|e| format!("Failed to restrict load: {}", e))?;
globals.set("loadfile", LuaValue::Nil)
.map_err(|e| format!("Failed to restrict loadfile: {}", e))?;
globals.set("dofile", LuaValue::Nil)
.map_err(|e| format!("Failed to restrict dofile: {}", e))?;
// Добавляем безопасные функции
Self::register_safe_functions(&lua)
.map_err(|e| format!("Failed to register safe functions: {}", e))?;
Ok(Self {
lua,
plugin_id: String::new(),
hooks: Vec::new(),
})
}
/// Зарегистрировать безопасные функции
fn register_safe_functions(lua: &Lua) -> LuaResult<()> {
let globals = lua.globals();
// Безопасные функции для логирования
let log_table = lua.create_table()?;
let lua_clone = lua.clone();
log_table.set("info", lua.create_function(move |_, msg: String| {
log::info!("[Plugin] {}", msg);
Ok(())
})?)?;
let lua_clone = lua.clone();
log_table.set("error", lua.create_function(move |_, msg: String| {
log::error!("[Plugin] {}", msg);
Ok(())
})?)?;
let lua_clone = lua.clone();
log_table.set("warn", lua.create_function(move |_, msg: String| {
log::warn!("[Plugin] {}", msg);
Ok(())
})?)?;
let lua_clone = lua.clone();
log_table.set("debug", lua.create_function(move |_, msg: String| {
log::debug!("[Plugin] {}", msg);
Ok(())
})?)?;
globals.set("log", log_table)?;
// Функция для работы с JSON
let json_table = lua.create_table()?;
let lua_clone = lua.clone();
json_table.set("encode", lua.create_function(move |lua, value: LuaValue| {
let json_value = Self::lua_value_to_json(value)?;
let json_str = serde_json::to_string(&json_value)
.map_err(|e| LuaError::external(e))?;
Ok(json_str)
})?)?;
let lua_clone = lua.clone();
json_table.set("decode", lua.create_function(move |lua, json_str: String| {
let json_value: Value = serde_json::from_str(&json_str)
.map_err(|e| LuaError::external(e))?;
Self::json_to_lua_value(lua, json_value)
})?)?;
globals.set("json", json_table)?;
// Функция для генерации UUID
let lua_clone = lua.clone();
globals.set("uuid", lua.create_function(move |_, ()| {
Ok(Uuid::new_v4().to_string())
})?)?;
Ok(())
}
/// Загрузить плагин из кода
pub fn load_plugin(&mut self, code: &str, path: &str) -> Result<PluginInfo, String> {
// Выполняем код плагина
self.lua.load(code).exec()
.map_err(|e| format!("Failed to execute plugin code: {}", e))?;
// Получаем метаданные плагина
let globals = self.lua.globals();
let plugin_table: mlua::Table = globals.get("PLUGIN")
.map_err(|_| "PLUGIN table not found".to_string())?;
let name: String = plugin_table.get("name")
.map_err(|e| format!("Failed to get plugin name: {}", e))?;
let version: String = plugin_table.get("version")
.map_err(|e| format!("Failed to get plugin version: {}", e))?;
let description: String = plugin_table.get("description")
.unwrap_or_else(|_| "No description".to_string());
let author: String = plugin_table.get("author")
.unwrap_or_else(|_| "Unknown".to_string());
// Генерируем ID плагина
let plugin_id = format!("{}-{}", name, Uuid::new_v4());
self.plugin_id = plugin_id.clone();
// Получаем хуки
let hooks_table: mlua::Table = plugin_table.get("hooks")
.unwrap_or_else(|_| self.lua.create_table().unwrap());
let mut hooks = Vec::new();
for pair in hooks_table.pairs::<String, mlua::Table>() {
match pair {
Ok((hook_name, hook_table)) => {
let function: String = hook_table.get("function")
.unwrap_or_else(|_| hook_name.clone());
let priority: u32 = hook_table.get("priority")
.unwrap_or(100);
let async_hook: bool = hook_table.get("async")
.unwrap_or(false);
hooks.push(PluginHook {
name: hook_name,
function,
priority,
async_hook,
});
}
Err(e) => {
log::warn!("Failed to parse hook: {}", e);
}
}
}
self.hooks = hooks.clone();
Ok(PluginInfo {
id: plugin_id,
name,
version,
description,
author,
path: path.to_string(),
state: format!("{:?}", PluginState::Loaded),
hooks,
})
}
/// Обработать событие
pub fn handle_event(&self, event: &PluginEvent) -> Result<(), String> {
let globals = self.lua.globals();
// Проверяем, есть ли функция для обработки событий
if let Ok(on_event) = globals.get::<_, mlua::Function>("on_event") {
let event_data = json!({
"type": format!("{:?}", event.event_type),
"data": event.data,
"source": event.source,
"timestamp": event.timestamp,
});
let event_json = serde_json::to_string(&event_data)
.map_err(|e| format!("Failed to serialize event: {}", e))?;
on_event.call::<_, ()>(event_json)
.map_err(|e| format!("Failed to call on_event: {}", e))?;
}
Ok(())
}
/// Выполнить хук
pub fn execute_hook(&self, function_name: &str, data: Value) -> Result<Value, String> {
let globals = self.lua.globals();
// Получаем функцию по имени
let hook_func: mlua::Function = globals.get(function_name)
.map_err(|e| format!("Hook function not found: {} - {}", function_name, e))?;
// Преобразуем данные в Lua значение
let lua_data = Self::json_to_lua_value(&self.lua, data)
.map_err(|e| format!("Failed to convert data to Lua: {}", e))?;
// Вызываем функцию
let result = hook_func.call::<_, LuaValue>(lua_data)
.map_err(|e| format!("Failed to execute hook: {}", e))?;
// Преобразуем результат обратно в JSON
Self::lua_value_to_json(result)
.map_err(|e| format!("Failed to convert result to JSON: {}", e))
}
/// Преобразовать Lua значение в JSON
fn lua_value_to_json(value: LuaValue) -> Result<Value, String> {
match value {
LuaValue::Nil => Ok(Value::Null),
LuaValue::Boolean(b) => Ok(Value::Bool(b)),
LuaValue::Integer(i) => Ok(Value::Number(i.into())),
LuaValue::Number(n) => {
// Попробуем преобразовать в integer если возможно
if n.fract() == 0.0 {
Ok(Value::Number((n as i64).into()))
} else {
serde_json::Number::from_f64(n)
.map(Value::Number)
.ok_or_else(|| "Invalid number".to_string())
}
}
LuaValue::String(s) => Ok(Value::String(s.to_string_lossy().to_string())),
LuaValue::Table(table) => {
let mut map = serde_json::Map::new();
for pair in table.pairs::<LuaValue, LuaValue>() {
match pair {
Ok((key, value)) => {
let key_str = match key {
LuaValue::String(s) => s.to_string_lossy().to_string(),
LuaValue::Integer(i) => i.to_string(),
LuaValue::Number(n) => n.to_string(),
_ => continue,
};
let value_json = Self::lua_value_to_json(value)?;
map.insert(key_str, value_json);
}
Err(e) => return Err(format!("Failed to parse table pair: {}", e)),
}
}
Ok(Value::Object(map))
}
_ => Err(format!("Unsupported Lua type: {:?}", value.type_name())),
}
}
/// Преобразовать JSON в Lua значение
fn json_to_lua_value(lua: &Lua, value: Value) -> LuaResult<LuaValue> {
match value {
Value::Null => Ok(LuaValue::Nil),
Value::Bool(b) => Ok(LuaValue::Boolean(b)),
Value::Number(n) => {
if let Some(i) = n.as_i64() {
Ok(LuaValue::Integer(i))
} else if let Some(f) = n.as_f64() {
Ok(LuaValue::Number(f))
} else {
Err(LuaError::external("Invalid number"))
}
}
Value::String(s) => Ok(LuaValue::String(lua.create_string(&s)?)),
Value::Array(arr) => {
let table = lua.create_table()?;
for (i, item) in arr.into_iter().enumerate() {
let lua_value = Self::json_to_lua_value(lua, item)?;
table.set(i + 1, lua_value)?;
}
Ok(LuaValue::Table(table))
}
Value::Object(obj) => {
let table = lua.create_table()?;
for (key, value) in obj {
let lua_value = Self::json_to_lua_value(lua, value)?;
table.set(key, lua_value)?;
}
Ok(LuaValue::Table(table))
}
}
}
}