Delete src/plugins/bad-sandbox.rs
This commit is contained in:
parent
c5ec1d432b
commit
fafa454c24
@ -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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user