Files
haex-hub-mirror/src-tauri/src/extension/permissions/validator.rs
haex a52e1b43fa Remove unused code and modernize Rust format strings
Applied cargo clippy fixes to clean up codebase:
- Removed unused imports (serde_json::json, std::collections::HashSet)
- Removed unused function encode_hex_for_log
- Modernized format strings to use inline variables
- Fixed clippy warnings for better code quality

All changes applied automatically by cargo clippy --fix
2025-11-02 14:48:01 +01:00

210 lines
7.2 KiB
Rust

// src-tauri/src/extension/permissions/validator.rs
use crate::database::core::{extract_table_names_from_sql, parse_single_statement};
use crate::database::error::DatabaseError;
use crate::extension::error::ExtensionError;
use crate::extension::permissions::manager::PermissionManager;
use crate::extension::permissions::types::Action;
use crate::AppState;
use sqlparser::ast::{Statement, TableFactor, TableObject};
use tauri::State;
pub struct SqlPermissionValidator;
impl SqlPermissionValidator {
/// Prüft ob eine Tabelle zur Extension gehört (basierend auf keyHash Präfix)
/// Format: {keyHash}_{extensionName}_{tableName}
fn is_own_table(extension_id: &str, table_name: &str) -> bool {
// Tabellennamen sind im Format: {keyHash}_{extensionName}_{tableName}
// extension_id ist der keyHash der Extension
table_name.starts_with(&format!("{extension_id}_"))
}
/// Validiert ein SQL-Statement gegen die Permissions einer Extension
pub async fn validate_sql(
app_state: &State<'_, AppState>,
extension_id: &str,
sql: &str,
) -> Result<(), ExtensionError> {
let statement = parse_single_statement(sql).map_err(|e| DatabaseError::ParseError {
reason: e.to_string(),
sql: sql.to_string(),
})?;
match &statement {
Statement::Query(_) => {
Self::validate_read_statement(app_state, extension_id, sql).await
}
Statement::Insert(_) | Statement::Update { .. } | Statement::Delete(_) => {
Self::validate_write_statement(app_state, extension_id, &statement).await
}
Statement::CreateTable(_) => {
Self::validate_create_statement(app_state, extension_id, &statement).await
}
Statement::AlterTable { .. } | Statement::Drop { .. } => {
Self::validate_schema_statement(app_state, extension_id, &statement).await
}
_ => Err(ExtensionError::ValidationError {
reason: format!("Statement type not allowed: {sql}"),
}),
}
}
/// Validiert READ-Operationen (SELECT)
async fn validate_read_statement(
app_state: &State<'_, AppState>,
extension_id: &str,
sql: &str,
) -> Result<(), ExtensionError> {
let tables = extract_table_names_from_sql(sql)?;
for table_name in tables {
PermissionManager::check_database_permission(
app_state,
extension_id,
Action::Database(super::types::DbAction::Read),
&table_name,
)
.await?;
}
Ok(())
}
/// Validiert WRITE-Operationen (INSERT, UPDATE, DELETE)
async fn validate_write_statement(
app_state: &State<'_, AppState>,
extension_id: &str,
statement: &Statement,
) -> Result<(), ExtensionError> {
let table_names = Self::extract_table_names_from_statement(statement)?;
for table_name in table_names {
PermissionManager::check_database_permission(
app_state,
extension_id,
Action::Database(super::types::DbAction::ReadWrite),
&table_name,
)
.await?;
}
Ok(())
}
/// Validiert CREATE TABLE
async fn validate_create_statement(
app_state: &State<'_, AppState>,
extension_id: &str,
statement: &Statement,
) -> Result<(), ExtensionError> {
if let Statement::CreateTable(create_table) = statement {
let table_name = create_table.name.to_string();
// Prüfe ob Extension überhaupt CREATE-Rechte hat (z.B. auf "*")
PermissionManager::check_database_permission(
app_state,
extension_id,
Action::Database(super::types::DbAction::Create),
&table_name,
)
.await?;
}
Ok(())
}
/// Validiert Schema-Änderungen (ALTER, DROP)
async fn validate_schema_statement(
app_state: &State<'_, AppState>,
extension_id: &str,
statement: &Statement,
) -> Result<(), ExtensionError> {
let table_names = Self::extract_table_names_from_statement(statement)?;
for table_name in table_names {
// ALTER/DROP benötigen WRITE-Rechte
PermissionManager::check_database_permission(
app_state,
extension_id,
Action::Database(super::types::DbAction::AlterDrop),
&table_name,
)
.await?;
}
Ok(())
}
/// Extrahiert alle Tabellennamen aus einem Statement
fn extract_table_names_from_statement(
statement: &Statement,
) -> Result<Vec<String>, ExtensionError> {
match statement {
Statement::Insert(insert) => Ok(vec![Self::extract_table_name_from_insert(insert)?]),
Statement::Update { table, .. } => {
Ok(vec![Self::extract_table_name_from_table_factor(
&table.relation,
)?])
}
Statement::Delete(delete) => Ok(vec![Self::extract_table_name_from_delete(delete)?]),
Statement::CreateTable(create_table) => Ok(vec![create_table.name.to_string()]),
Statement::AlterTable { name, .. } => Ok(vec![name.to_string()]),
Statement::Drop { names, .. } => {
Ok(names.iter().map(|name| name.to_string()).collect())
}
_ => Ok(vec![]),
}
}
/// Extrahiert Tabellenname aus INSERT
fn extract_table_name_from_insert(
insert: &sqlparser::ast::Insert,
) -> Result<String, ExtensionError> {
match &insert.table {
TableObject::TableName(name) => Ok(name.to_string()),
_ => Err(DatabaseError::NoTableError {
sql: insert.to_string(),
}
.into()),
}
}
/// Extrahiert Tabellenname aus TableFactor
fn extract_table_name_from_table_factor(
table_factor: &TableFactor,
) -> Result<String, ExtensionError> {
match table_factor {
TableFactor::Table { name, .. } => Ok(name.to_string()),
_ => Err(DatabaseError::StatementError {
reason: "Complex table references not supported".to_string(),
}
.into()),
}
}
/// Extrahiert Tabellenname aus DELETE
fn extract_table_name_from_delete(
delete: &sqlparser::ast::Delete,
) -> Result<String, ExtensionError> {
use sqlparser::ast::FromTable;
let table_name = match &delete.from {
FromTable::WithFromKeyword(tables) | FromTable::WithoutKeyword(tables) => {
if !tables.is_empty() {
Self::extract_table_name_from_table_factor(&tables[0].relation)?
} else if !delete.tables.is_empty() {
delete.tables[0].to_string()
} else {
return Err(DatabaseError::NoTableError {
sql: delete.to_string(),
}
.into());
}
}
};
Ok(table_name)
}
}