mirror of
https://github.com/haexhub/haex-hub.git
synced 2025-12-16 22:20:51 +01:00
zwischenstand
This commit is contained in:
@ -1,13 +1,74 @@
|
||||
// database/core.rs
|
||||
use crate::database::DbConnection;
|
||||
use rusqlite::{Connection, OpenFlags};
|
||||
use serde_json::json;
|
||||
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
||||
use rusqlite::{
|
||||
types::{Value as RusqliteValue, ValueRef},
|
||||
Connection, OpenFlags, ToSql,
|
||||
};
|
||||
use serde_json::Value as JsonValue;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use tauri::State;
|
||||
// --- Hilfsfunktion: Konvertiert JSON Value zu etwas, das rusqlite versteht ---
|
||||
// Diese Funktion ist etwas knifflig wegen Ownership und Lifetimes.
|
||||
// Eine einfachere Variante ist oft, direkt rusqlite::types::Value zu erstellen.
|
||||
// Hier ein Beispiel, das owned Values erstellt (braucht evtl. Anpassung je nach rusqlite-Version/Nutzung)
|
||||
fn json_to_rusqlite_value(json_val: &JsonValue) -> Result<RusqliteValue, String> {
|
||||
match json_val {
|
||||
JsonValue::Null => Ok(RusqliteValue::Null),
|
||||
JsonValue::Bool(b) => Ok(RusqliteValue::Integer(*b as i64)), // SQLite hat keinen BOOLEAN
|
||||
JsonValue::Number(n) => {
|
||||
if let Some(i) = n.as_i64() {
|
||||
Ok(RusqliteValue::Integer(i))
|
||||
} else if let Some(f) = n.as_f64() {
|
||||
Ok(RusqliteValue::Real(f))
|
||||
} else {
|
||||
Err("Ungültiger Zahlenwert".to_string())
|
||||
}
|
||||
}
|
||||
JsonValue::String(s) => Ok(RusqliteValue::Text(s.clone())),
|
||||
JsonValue::Array(_) | JsonValue::Object(_) => {
|
||||
// SQLite kann Arrays/Objects nicht direkt speichern (außer als TEXT/BLOB)
|
||||
// Konvertiere sie zu JSON-Strings, wenn das gewünscht ist
|
||||
Ok(RusqliteValue::Text(
|
||||
serde_json::to_string(json_val).map_err(|e| e.to_string())?,
|
||||
))
|
||||
// Oder gib einen Fehler zurück, wenn Arrays/Objekte nicht erlaubt sind
|
||||
// Err("Arrays oder Objekte werden nicht direkt als Parameter unterstützt".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Tauri Command für INSERT/UPDATE/DELETE ---
|
||||
#[tauri::command]
|
||||
pub async fn execute(
|
||||
sql: String,
|
||||
params: Vec<JsonValue>,
|
||||
state: &State<'_, DbConnection>,
|
||||
) -> Result<usize, String> {
|
||||
// Gibt Anzahl betroffener Zeilen zurück
|
||||
|
||||
let params_converted: Vec<RusqliteValue> = params
|
||||
.iter()
|
||||
.map(json_to_rusqlite_value)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let params_sql: Vec<&dyn ToSql> = params_converted.iter().map(|v| v as &dyn ToSql).collect();
|
||||
|
||||
let db_lock = state
|
||||
.0
|
||||
.lock()
|
||||
.map_err(|e| format!("Mutex Lock Fehler: {}", e))?;
|
||||
let conn = db_lock.as_ref().ok_or("Keine Datenbankverbindung")?;
|
||||
|
||||
let affected_rows = conn
|
||||
.execute(&sql, ¶ms_sql[..])
|
||||
.map_err(|e| format!("SQL Execute Fehler: {}", e))?;
|
||||
|
||||
Ok(affected_rows)
|
||||
}
|
||||
|
||||
/// Führt SQL-Schreiboperationen (INSERT, UPDATE, DELETE, CREATE) ohne Berechtigungsprüfung aus
|
||||
pub async fn execute(
|
||||
/* pub async fn execute(
|
||||
sql: &str,
|
||||
params: &[String],
|
||||
state: &State<'_, DbConnection>,
|
||||
@ -26,14 +87,107 @@ pub async fn execute(
|
||||
"last_insert_id": last_id
|
||||
}))
|
||||
.map_err(|e| format!("JSON-Serialisierungsfehler: {}", e))?)
|
||||
} */
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn select(
|
||||
sql: String,
|
||||
params: Vec<JsonValue>, // Parameter als JSON Values empfangen
|
||||
state: &State<'_, DbConnection>,
|
||||
) -> Result<Vec<Vec<JsonValue>>, String> {
|
||||
// Ergebnis als Vec<RowObject>
|
||||
|
||||
// Konvertiere JSON Params zu rusqlite Values für die Abfrage
|
||||
// Wir sammeln sie als owned Values, da `params_from_iter` Referenzen braucht,
|
||||
// was mit lokalen Konvertierungen schwierig ist.
|
||||
let params_converted: Vec<RusqliteValue> = params
|
||||
.iter()
|
||||
.map(json_to_rusqlite_value)
|
||||
.collect::<Result<Vec<_>, _>>()?; // Sammle Ergebnisse, gibt Fehler weiter
|
||||
|
||||
// Konvertiere zu Slice von ToSql-Referenzen (erfordert, dass die Values leben)
|
||||
let params_sql: Vec<&dyn ToSql> = params_converted.iter().map(|v| v as &dyn ToSql).collect();
|
||||
|
||||
// Zugriff auf die Verbindung (blockierend, okay für SQLite in vielen Fällen)
|
||||
let db_lock = state
|
||||
.0
|
||||
.lock()
|
||||
.map_err(|e| format!("Mutex Lock Fehler: {}", e))?;
|
||||
let conn = db_lock.as_ref().ok_or("Keine Datenbankverbindung")?;
|
||||
|
||||
let mut stmt = conn
|
||||
.prepare(&sql)
|
||||
.map_err(|e| format!("SQL Prepare Fehler: {}", e))?;
|
||||
let column_names: Vec<String> = stmt
|
||||
.column_names()
|
||||
.into_iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let num_columns = column_names.len();
|
||||
|
||||
let mut rows = stmt
|
||||
.query(¶ms_sql[..])
|
||||
.map_err(|e| format!("SQL Query Fehler: {}", e))?;
|
||||
let mut result_vec: Vec<Vec<JsonValue>> = Vec::new();
|
||||
|
||||
println!();
|
||||
println!();
|
||||
println!();
|
||||
println!();
|
||||
|
||||
while let Some(row) = rows.next().map_err(|e| format!("Row Next Fehler: {}", e))? {
|
||||
//let mut row_map = HashMap::new();
|
||||
let mut row_data: Vec<JsonValue> = Vec::with_capacity(num_columns);
|
||||
for i in 0..num_columns {
|
||||
let col_name = &column_names[i];
|
||||
|
||||
println!(
|
||||
"--- Processing Column --- Index: {}, Name: '{}'",
|
||||
i, col_name
|
||||
);
|
||||
let value_ref = row
|
||||
.get_ref(i)
|
||||
.map_err(|e| format!("Get Ref Fehler Spalte {}: {}", i, e))?;
|
||||
|
||||
// Wandle rusqlite ValueRef zurück zu serde_json Value
|
||||
let json_val = match value_ref {
|
||||
ValueRef::Null => JsonValue::Null,
|
||||
ValueRef::Integer(i) => JsonValue::Number(i.into()),
|
||||
ValueRef::Real(f) => JsonValue::Number(
|
||||
serde_json::Number::from_f64(f).unwrap_or(serde_json::Number::from(0)),
|
||||
), // Fallback für NaN/Infinity
|
||||
ValueRef::Text(t) => {
|
||||
let s = String::from_utf8_lossy(t).to_string();
|
||||
// Versuche, als JSON zu parsen, falls es ursprünglich ein Array/Objekt war
|
||||
//serde_json::from_str(&s).unwrap_or(JsonValue::String(s))
|
||||
JsonValue::String(s)
|
||||
}
|
||||
ValueRef::Blob(b) => {
|
||||
// BLOBs z.B. als Base64-String zurückgeben
|
||||
JsonValue::String(STANDARD.encode(b))
|
||||
}
|
||||
};
|
||||
println!(
|
||||
"new row: name: {} with value: {}",
|
||||
column_names[i].clone(),
|
||||
json_val,
|
||||
);
|
||||
row_data.push(json_val);
|
||||
//row_map.insert(column_names[i].clone(), json_val);
|
||||
}
|
||||
//result_vec.push(row_map);
|
||||
result_vec.push(row_data);
|
||||
}
|
||||
|
||||
Ok(result_vec)
|
||||
}
|
||||
|
||||
/// Führt SQL-Leseoperationen (SELECT) ohne Berechtigungsprüfung aus
|
||||
pub async fn select(
|
||||
/* pub async fn select(
|
||||
sql: &str,
|
||||
params: &[String],
|
||||
state: &State<'_, DbConnection>,
|
||||
) -> Result<Vec<Vec<String>>, String> {
|
||||
) -> Result<Vec<Vec<Option<String>>>, String> {
|
||||
let db = state.0.lock().map_err(|e| format!("Mutex-Fehler: {}", e))?;
|
||||
let conn = db.as_ref().ok_or("Keine Datenbankverbindung vorhanden")?;
|
||||
|
||||
@ -52,16 +206,20 @@ pub async fn select(
|
||||
{
|
||||
let mut row_data = Vec::new();
|
||||
for i in 0..columns {
|
||||
let value: String = row
|
||||
let value = row
|
||||
.get(i)
|
||||
.map_err(|e| format!("Datentypfehler in Spalte {}: {}", i, e))?;
|
||||
row_data.push(value);
|
||||
}
|
||||
/* println!(
|
||||
"Select Row Data: {}",
|
||||
&row_data.clone().join("").to_string()
|
||||
); */
|
||||
result.push(row_data);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
} */
|
||||
|
||||
/// Öffnet und initialisiert eine Datenbank mit Verschlüsselung
|
||||
pub fn open_and_init_db(path: &str, key: &str, create: bool) -> Result<Connection, String> {
|
||||
@ -75,6 +233,9 @@ pub fn open_and_init_db(path: &str, key: &str, create: bool) -> Result<Connectio
|
||||
conn.pragma_update(None, "key", key)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
conn.execute_batch("SELECT count(*) from haex_extensions")
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
|
||||
@ -1,30 +1,30 @@
|
||||
// database/mod.rs
|
||||
pub mod core;
|
||||
|
||||
use rusqlite::{Connection, OpenFlags};
|
||||
use rusqlite::Connection;
|
||||
use serde_json::Value as JsonValue;
|
||||
use std::path::Path;
|
||||
use std::sync::Mutex;
|
||||
use tauri::{path::BaseDirectory, AppHandle, Manager, State};
|
||||
|
||||
pub struct DbConnection(pub Mutex<Option<Connection>>);
|
||||
|
||||
// Öffentliche Funktionen für direkten Datenbankzugriff
|
||||
#[tauri::command]
|
||||
pub async fn sql_select(
|
||||
sql: String,
|
||||
params: Vec<String>,
|
||||
params: Vec<JsonValue>,
|
||||
state: State<'_, DbConnection>,
|
||||
) -> Result<Vec<Vec<String>>, String> {
|
||||
core::select(&sql, ¶ms, &state).await
|
||||
) -> Result<Vec<Vec<JsonValue>>, String> {
|
||||
core::select(sql, params, &state).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn sql_execute(
|
||||
sql: String,
|
||||
params: Vec<String>,
|
||||
params: Vec<JsonValue>,
|
||||
state: State<'_, DbConnection>,
|
||||
) -> Result<String, String> {
|
||||
core::execute(&sql, ¶ms, &state).await
|
||||
) -> Result<usize, String> {
|
||||
core::execute(sql, params, &state).await
|
||||
}
|
||||
|
||||
/// Erstellt eine verschlüsselte Datenbank
|
||||
@ -58,7 +58,62 @@ pub fn create_encrypted_database(
|
||||
}
|
||||
}
|
||||
|
||||
// Neue Datenbank erstellen
|
||||
//core::copy_file(&resource_path, &path)?;
|
||||
|
||||
println!(
|
||||
"Öffne unverschlüsselte Datenbank: {}",
|
||||
resource_path.as_path().display()
|
||||
);
|
||||
|
||||
let conn = Connection::open(&resource_path).map_err(|e| {
|
||||
format!(
|
||||
"Fehler beim Öffnen der kopierten Datenbank: {}",
|
||||
e.to_string()
|
||||
)
|
||||
})?;
|
||||
|
||||
//let conn = Connection::open(&resource_path)?;
|
||||
|
||||
println!("Hänge neue, verschlüsselte Datenbank an unter '{}'", &path);
|
||||
// ATTACH DATABASE 'Dateiname' AS Alias KEY 'Passwort';
|
||||
conn.execute("ATTACH DATABASE ?1 AS encrypted KEY ?2;", [&path, &key])
|
||||
.map_err(|e| format!("Fehler bei ATTACH DATABASE: {}", e.to_string()))?;
|
||||
|
||||
println!(
|
||||
"Exportiere Daten von 'main' nach 'encrypted' mit password {} ...",
|
||||
&key
|
||||
);
|
||||
|
||||
match conn.query_row("SELECT sqlcipher_export('encrypted');", [], |_row| Ok(())) {
|
||||
Ok(_) => {
|
||||
println!(">>> sqlcipher_export erfolgreich ausgeführt (Rückgabewert ignoriert).");
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("!!! FEHLER während sqlcipher_export: {}", e);
|
||||
conn.execute("DETACH DATABASE encrypted;", []).ok(); // Versuche zu detachen
|
||||
return Err(e.to_string()); // Gib den Fehler zurück
|
||||
}
|
||||
}
|
||||
// sqlcipher_export('Alias') kopiert Schema und Daten von 'main' zur Alias-DB
|
||||
/* conn.execute("SELECT sqlcipher_export('encrypted');", [])
|
||||
.map_err(|e| {
|
||||
format!(
|
||||
"Fehler bei SELECT sqlcipher_export('encrypted'): {}",
|
||||
e.to_string()
|
||||
)
|
||||
})?; */
|
||||
|
||||
println!("Löse die verschlüsselte Datenbank vom Handle...");
|
||||
conn.execute("DETACH DATABASE encrypted;", [])
|
||||
.map_err(|e| format!("Fehler bei DETACH DATABASE: {}", e.to_string()))?;
|
||||
|
||||
println!("Datenbank erfolgreich nach '{}' verschlüsselt.", &path);
|
||||
println!(
|
||||
"Die Originaldatei '{}' ist unverändert.",
|
||||
resource_path.as_path().display()
|
||||
);
|
||||
|
||||
/* // Neue Datenbank erstellen
|
||||
let conn = Connection::open_with_flags(
|
||||
&path,
|
||||
OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE,
|
||||
@ -77,7 +132,7 @@ pub fn create_encrypted_database(
|
||||
"Fehler beim Testen der verschlüsselten Datenbank: {}",
|
||||
e.to_string()
|
||||
));
|
||||
}
|
||||
} */
|
||||
|
||||
// 2. VERSUCHEN, EINE SQLCIPHER-SPEZIFISCHE OPERATION AUSZUFÜHREN
|
||||
println!("Prüfe SQLCipher-Aktivität mit 'PRAGMA cipher_version;'...");
|
||||
@ -88,7 +143,7 @@ pub fn create_encrypted_database(
|
||||
Ok(version) => {
|
||||
println!("SQLCipher ist aktiv! Version: {}", version);
|
||||
|
||||
// Fahre mit normalen Operationen fort
|
||||
/* // Fahre mit normalen Operationen fort
|
||||
println!("Erstelle Tabelle 'benutzer'...");
|
||||
conn.execute(
|
||||
"CREATE TABLE benutzer (id INTEGER PRIMARY KEY, name TEXT NOT NULL)",
|
||||
@ -100,7 +155,7 @@ pub fn create_encrypted_database(
|
||||
.map_err(|e| {
|
||||
format!("Fehler beim Verschlüsseln der Datenbank: {}", e.to_string())
|
||||
})?;
|
||||
println!("Benutzer hinzugefügt.");
|
||||
println!("Benutzer hinzugefügt."); */
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("FEHLER: SQLCipher scheint NICHT aktiv zu sein!");
|
||||
|
||||
181
src-tauri/src/extension/core.rs
Normal file
181
src-tauri/src/extension/core.rs
Normal file
@ -0,0 +1,181 @@
|
||||
use mime;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use tauri::{
|
||||
http::{Request, Response, Uri},
|
||||
AppHandle, Error as TauriError, Manager, Runtime,
|
||||
};
|
||||
|
||||
pub fn copy_directory(source: String, destination: String) -> Result<(), String> {
|
||||
println!(
|
||||
"Kopiere Verzeichnis von '{}' nach '{}'",
|
||||
source, destination
|
||||
);
|
||||
|
||||
let source_path = PathBuf::from(&source);
|
||||
let destination_path = PathBuf::from(&destination);
|
||||
|
||||
if !source_path.exists() || !source_path.is_dir() {
|
||||
return Err(format!(
|
||||
"Quellverzeichnis '{}' nicht gefunden oder ist kein Verzeichnis.",
|
||||
source
|
||||
));
|
||||
}
|
||||
|
||||
// Optionen für fs_extra::dir::copy
|
||||
let mut options = fs_extra::dir::CopyOptions::new();
|
||||
options.overwrite = true; // Überschreibe Zieldateien, falls sie existieren
|
||||
options.copy_inside = true; // Kopiere den *Inhalt* des Quellordners in den Zielordner
|
||||
// options.content_only = true; // Alternative: nur Inhalt kopieren, Zielordner muss existieren
|
||||
options.buffer_size = 64000; // Standard-Puffergröße, kann angepasst werden
|
||||
|
||||
// Führe die Kopieroperation aus
|
||||
match fs_extra::dir::copy(&source_path, &destination_path, &options) {
|
||||
Ok(bytes_copied) => {
|
||||
println!("Verzeichnis erfolgreich kopiert ({} bytes)", bytes_copied);
|
||||
Ok(()) // Erfolg signalisieren
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Fehler beim Kopieren des Verzeichnisses: {}", e);
|
||||
Err(format!("Fehler beim Kopieren: {}", e.to_string())) // Fehler als String zurückgeben
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_secure_extension_asset_path<R: Runtime>(
|
||||
app_handle: &AppHandle<R>,
|
||||
extension_id: &str,
|
||||
requested_asset_path: &str,
|
||||
) -> Result<PathBuf, String> {
|
||||
// 1. Validiere die Extension ID
|
||||
if extension_id.is_empty()
|
||||
|| !extension_id
|
||||
.chars()
|
||||
.all(|c| c.is_ascii_alphanumeric() || c == '-')
|
||||
{
|
||||
return Err(format!("Ungültige Extension ID: {}", extension_id));
|
||||
}
|
||||
|
||||
// 2. Bestimme das Basisverzeichnis für alle Erweiterungen (Resource Directory)
|
||||
let base_extensions_dir = app_handle
|
||||
.path()
|
||||
.resource_dir() // Korrekt für Ressourcen
|
||||
// Wenn du stattdessen App Local Data willst: .app_local_data_dir()
|
||||
.map_err(|e: TauriError| format!("Basis-Verzeichnis nicht gefunden: {}", e))?
|
||||
.join("extensions");
|
||||
|
||||
// 3. Verzeichnis für die spezifische Erweiterung
|
||||
let specific_extension_dir = base_extensions_dir.join(extension_id);
|
||||
|
||||
// 4. Bereinige den angeforderten Asset-Pfad
|
||||
let clean_relative_path = requested_asset_path
|
||||
.replace('\\', "/")
|
||||
.trim_start_matches('/')
|
||||
.split('/')
|
||||
.filter(|&part| !part.is_empty() && part != "." && part != "..")
|
||||
.collect::<PathBuf>();
|
||||
|
||||
if clean_relative_path.as_os_str().is_empty() && requested_asset_path != "/" {
|
||||
return Err("Leerer oder ungültiger Asset-Pfad".to_string());
|
||||
}
|
||||
|
||||
// 5. Setze den finalen Pfad zusammen
|
||||
let final_path = specific_extension_dir.join(clean_relative_path);
|
||||
|
||||
// 6. SICHERHEITSCHECK (wie vorher)
|
||||
match final_path.canonicalize() {
|
||||
Ok(canonical_path) => {
|
||||
let canonical_base = specific_extension_dir.canonicalize().map_err(|e| {
|
||||
format!(
|
||||
"Kann Basis-Pfad '{}' nicht kanonisieren: {}",
|
||||
specific_extension_dir.display(),
|
||||
e
|
||||
)
|
||||
})?;
|
||||
if canonical_path.starts_with(&canonical_base) {
|
||||
Ok(canonical_path)
|
||||
} else {
|
||||
eprintln!( /* ... Sicherheitswarnung ... */ );
|
||||
Err("Ungültiger oder nicht erlaubter Asset-Pfad (kanonisch)".to_string())
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
// Fehler bei canonicalize (z.B. Pfad existiert nicht)
|
||||
if final_path.starts_with(&specific_extension_dir) {
|
||||
Ok(final_path) // Nicht-kanonisierten Pfad zurückgeben
|
||||
} else {
|
||||
eprintln!( /* ... Sicherheitswarnung ... */ );
|
||||
Err("Ungültiger oder nicht erlaubter Asset-Pfad (nicht kanonisiert)".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_extension_protocol<R: Runtime>(
|
||||
app_handle: &AppHandle<R>,
|
||||
request: &Request<Vec<u8>>,
|
||||
) -> Result<Response<Vec<u8>>, Box<dyn std::error::Error>> {
|
||||
let uri_ref = request.uri(); // uri_ref ist &Uri
|
||||
println!("Protokoll Handler für: {}", uri_ref);
|
||||
|
||||
let uri_string = uri_ref.to_string(); // Konvertiere zu String
|
||||
let parsed_uri = Uri::from_str(&uri_string)?; // Parse aus &str
|
||||
|
||||
let extension_id = parsed_uri
|
||||
.host()
|
||||
.ok_or("Kein Host (Extension ID) in URI gefunden")?
|
||||
.to_string();
|
||||
|
||||
let requested_asset_path = parsed_uri.path();
|
||||
|
||||
let asset_path_to_load = if requested_asset_path == "/" || requested_asset_path.is_empty() {
|
||||
"index.html"
|
||||
} else {
|
||||
requested_asset_path
|
||||
};
|
||||
|
||||
// Sicheren Dateisystempfad auflösen (nutzt jetzt AppHandle)
|
||||
let absolute_secure_path =
|
||||
resolve_secure_extension_asset_path(app_handle, &extension_id, asset_path_to_load)?;
|
||||
|
||||
// Datei lesen und Response erstellen (Code wie vorher)
|
||||
match fs::read(&absolute_secure_path) {
|
||||
Ok(content) => {
|
||||
let mime_type = mime_guess::from_path(&absolute_secure_path)
|
||||
.first_or(mime::APPLICATION_OCTET_STREAM)
|
||||
.to_string();
|
||||
println!(
|
||||
"Liefere {} ({}) für Extension '{}'",
|
||||
absolute_secure_path.display(),
|
||||
mime_type,
|
||||
extension_id
|
||||
);
|
||||
// *** KORREKTUR: Verwende Response::builder() ***
|
||||
Response::builder()
|
||||
.status(200)
|
||||
.header("Content-Type", mime_type) // Setze Header über .header()
|
||||
.body(content) // body() gibt Result<Response<Vec<u8>>, Error> zurück
|
||||
.map_err(|e| e.into()) // Wandle http::Error in Box<dyn Error> um
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"Fehler beim Lesen der Datei {}: {}",
|
||||
absolute_secure_path.display(),
|
||||
e
|
||||
);
|
||||
let status_code = if e.kind() == std::io::ErrorKind::NotFound {
|
||||
404
|
||||
} else if e.kind() == std::io::ErrorKind::PermissionDenied {
|
||||
403
|
||||
} else {
|
||||
500
|
||||
};
|
||||
// *** KORREKTUR: Verwende Response::builder() auch für Fehler ***
|
||||
Response::builder()
|
||||
.status(status_code)
|
||||
.body(Vec::new()) // Leerer Body für Fehler
|
||||
.map_err(|e| e.into()) // Wandle http::Error in Box<dyn Error> um
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,11 @@
|
||||
mod permissions;
|
||||
|
||||
use crate::database;
|
||||
use crate::database::DbConnection;
|
||||
use crate::models::ExtensionState;
|
||||
use serde_json::Value as JsonValue;
|
||||
use std::collections::HashMap;
|
||||
use tauri::{AppHandle, State};
|
||||
|
||||
// Extension-bezogene Funktionen mit extension_-Präfix
|
||||
/// Lädt eine Extension aus einer Manifest-Datei
|
||||
/* #[tauri::command]
|
||||
@ -25,11 +27,11 @@ pub async fn extension_sql_select(
|
||||
app: AppHandle,
|
||||
extension_id: String,
|
||||
sql: String,
|
||||
params: Vec<String>,
|
||||
params: Vec<JsonValue>,
|
||||
state: State<'_, DbConnection>,
|
||||
) -> Result<Vec<Vec<String>>, String> {
|
||||
) -> Result<Vec<Vec<JsonValue>>, String> {
|
||||
permissions::check_read_permission(&app, &extension_id, &sql).await?;
|
||||
database::core::select(&sql, ¶ms, &state).await
|
||||
database::core::select(sql, params, &state).await
|
||||
}
|
||||
|
||||
/// Führt SQL-Schreiboperationen mit Berechtigungsprüfung aus
|
||||
@ -38,9 +40,9 @@ pub async fn extension_sql_execute(
|
||||
app: AppHandle,
|
||||
extension_id: String,
|
||||
sql: String,
|
||||
params: Vec<String>,
|
||||
params: Vec<JsonValue>,
|
||||
state: State<'_, DbConnection>,
|
||||
) -> Result<String, String> {
|
||||
) -> Result<usize, String> {
|
||||
permissions::check_write_permission(&app, &extension_id, &sql).await?;
|
||||
database::core::execute(&sql, ¶ms, &state).await
|
||||
database::core::execute(sql, params, &state).await
|
||||
}
|
||||
|
||||
@ -1 +1,8 @@
|
||||
pub mod core;
|
||||
pub mod database;
|
||||
use tauri;
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn copy_directory(source: String, destination: String) -> Result<(), String> {
|
||||
core::copy_directory(source, destination)
|
||||
}
|
||||
|
||||
@ -9,7 +9,33 @@ use std::sync::Mutex;
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
let protocol_name = "haex-extension";
|
||||
|
||||
tauri::Builder::default()
|
||||
/* .register_uri_scheme_protocol(protocol_name, move |app_handle, request| {
|
||||
// Extrahiere den Request aus dem Kontext
|
||||
//let request = context.request();
|
||||
// Rufe die Handler-Logik auf
|
||||
match extension::core::handle_extension_protocol(0, &request) {
|
||||
Ok(response) => response, // Gib die erfolgreiche Response zurück
|
||||
Err(e) => {
|
||||
// Logge den Fehler
|
||||
eprintln!("Fehler im Protokoll-Handler für '{}': {}", request.uri(), e);
|
||||
// Gib eine generische 500er Fehler-Response zurück
|
||||
Response::builder()
|
||||
.status(500)
|
||||
.mimetype("text/plain") // Einfacher Text für die Fehlermeldung
|
||||
.body(format!("Internal Server Error: {}", e).into_bytes()) // Body als Vec<u8>
|
||||
.unwrap() // .body() kann hier nicht fehlschlagen
|
||||
}
|
||||
}
|
||||
}) */
|
||||
/* .setup(move |app| {
|
||||
// Der .setup Hook ist jetzt nur noch für andere Initialisierungen da
|
||||
// Der AppHandle ist hier nicht mehr nötig für die Protokoll-Registrierung
|
||||
println!("App Setup abgeschlossen.");
|
||||
Ok(())
|
||||
}) */
|
||||
.plugin(tauri_plugin_http::init())
|
||||
.manage(DbConnection(Mutex::new(None)))
|
||||
.manage(ExtensionState::default())
|
||||
@ -26,7 +52,7 @@ pub fn run() {
|
||||
database::sql_select,
|
||||
extension::database::extension_sql_execute,
|
||||
extension::database::extension_sql_select,
|
||||
//browser::create_tab
|
||||
extension::copy_directory //browser::create_tab
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
||||
Reference in New Issue
Block a user