mirror of
https://github.com/haexhub/haex-hub.git
synced 2025-12-16 14:10:52 +01:00
Add permission check handlers for extensions
- Add check.rs with Tauri commands for checking web, database, and filesystem permissions - Implement handlePermissionsMethodAsync in frontend to route permission checks - Register permission check commands in lib.rs - Add toast notification for permission denied errors in web requests - Extensions can now check permissions before operations via SDK
This commit is contained in:
64
src-tauri/src/extension/permissions/check.rs
Normal file
64
src-tauri/src/extension/permissions/check.rs
Normal file
@ -0,0 +1,64 @@
|
||||
// src-tauri/src/extension/permissions/commands.rs
|
||||
|
||||
use crate::extension::error::ExtensionError;
|
||||
use crate::extension::permissions::manager::PermissionManager;
|
||||
use crate::AppState;
|
||||
use tauri::State;
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn check_web_permission(
|
||||
extension_id: String,
|
||||
method: String,
|
||||
url: String,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<(), ExtensionError> {
|
||||
PermissionManager::check_web_permission(&state, &extension_id, &method, &url).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn check_database_permission(
|
||||
extension_id: String,
|
||||
resource: String,
|
||||
operation: String,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<(), ExtensionError> {
|
||||
let action = match operation.as_str() {
|
||||
"read" => crate::extension::permissions::types::Action::Database(
|
||||
crate::extension::permissions::types::DbAction::Read,
|
||||
),
|
||||
"write" => crate::extension::permissions::types::Action::Database(
|
||||
crate::extension::permissions::types::DbAction::ReadWrite,
|
||||
),
|
||||
_ => {
|
||||
return Err(ExtensionError::ValidationError {
|
||||
reason: format!("Invalid database operation: {}", operation),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
PermissionManager::check_database_permission(&state, &extension_id, action, &resource).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn check_filesystem_permission(
|
||||
extension_id: String,
|
||||
path: String,
|
||||
operation: String,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<(), ExtensionError> {
|
||||
let action = match operation.as_str() {
|
||||
"read" => crate::extension::permissions::types::Action::Filesystem(
|
||||
crate::extension::permissions::types::FsAction::Read,
|
||||
),
|
||||
"write" => crate::extension::permissions::types::Action::Filesystem(
|
||||
crate::extension::permissions::types::FsAction::ReadWrite,
|
||||
),
|
||||
_ => {
|
||||
return Err(ExtensionError::ValidationError {
|
||||
reason: format!("Invalid filesystem operation: {}", operation),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
PermissionManager::check_filesystem_permission(&state, &extension_id, action, &path).await
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
pub mod check;
|
||||
pub mod manager;
|
||||
pub mod types;
|
||||
pub mod validator;
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
mod crdt;
|
||||
mod database;
|
||||
mod extension;
|
||||
use crate::{crdt::hlc::HlcService, database::DbConnection, extension::core::ExtensionManager};
|
||||
use crate::{
|
||||
crdt::hlc::HlcService,
|
||||
database::DbConnection,
|
||||
extension::{
|
||||
core::ExtensionManager,
|
||||
webview::ExtensionWebviewManager,
|
||||
}
|
||||
};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tauri::Manager;
|
||||
|
||||
@ -9,10 +16,15 @@ pub mod table_names {
|
||||
include!(concat!(env!("OUT_DIR"), "/tableNames.rs"));
|
||||
}
|
||||
|
||||
pub mod event_names {
|
||||
include!(concat!(env!("OUT_DIR"), "/eventNames.rs"));
|
||||
}
|
||||
|
||||
pub struct AppState {
|
||||
pub db: DbConnection,
|
||||
pub hlc: Mutex<HlcService>,
|
||||
pub extension_manager: ExtensionManager,
|
||||
pub extension_webview_manager: ExtensionWebviewManager,
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
@ -54,6 +66,7 @@ pub fn run() {
|
||||
db: DbConnection(Arc::new(Mutex::new(None))),
|
||||
hlc: Mutex::new(HlcService::new()),
|
||||
extension_manager: ExtensionManager::new(),
|
||||
extension_webview_manager: ExtensionWebviewManager::new(),
|
||||
})
|
||||
//.manage(ExtensionState::default())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
@ -80,6 +93,9 @@ pub fn run() {
|
||||
extension::database::extension_sql_select,
|
||||
extension::web::extension_web_fetch,
|
||||
extension::web::extension_web_open,
|
||||
extension::permissions::check::check_web_permission,
|
||||
extension::permissions::check::check_database_permission,
|
||||
extension::permissions::check::check_filesystem_permission,
|
||||
extension::get_all_dev_extensions,
|
||||
extension::get_all_extensions,
|
||||
extension::get_extension_info,
|
||||
@ -89,6 +105,11 @@ pub fn run() {
|
||||
extension::preview_extension,
|
||||
extension::remove_dev_extension,
|
||||
extension::remove_extension,
|
||||
extension::open_extension_webview_window,
|
||||
extension::close_extension_webview_window,
|
||||
extension::focus_extension_webview_window,
|
||||
extension::update_extension_webview_window_position,
|
||||
extension::update_extension_webview_window_size,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import type { IHaexHubExtension } from '~/types/haexhub'
|
||||
import type { ExtensionRequest } from './types'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
export async function handlePermissionsMethodAsync(
|
||||
request: ExtensionRequest,
|
||||
@ -9,6 +10,102 @@ export async function handlePermissionsMethodAsync(
|
||||
throw new Error('Extension not found')
|
||||
}
|
||||
|
||||
// TODO: Implementiere Permission Request UI
|
||||
throw new Error('Permission methods not yet implemented')
|
||||
const { method, params } = request
|
||||
|
||||
if (method === 'permissions.web.check') {
|
||||
return await checkWebPermissionAsync(params, extension)
|
||||
}
|
||||
|
||||
if (method === 'permissions.database.check') {
|
||||
return await checkDatabasePermissionAsync(params, extension)
|
||||
}
|
||||
|
||||
if (method === 'permissions.filesystem.check') {
|
||||
return await checkFilesystemPermissionAsync(params, extension)
|
||||
}
|
||||
|
||||
throw new Error(`Unknown permission method: ${method}`)
|
||||
}
|
||||
|
||||
async function checkWebPermissionAsync(
|
||||
params: Record<string, unknown>,
|
||||
extension: IHaexHubExtension,
|
||||
) {
|
||||
const url = params.url as string
|
||||
const method = (params.method as string) || 'GET'
|
||||
|
||||
if (!url) {
|
||||
throw new Error('URL is required')
|
||||
}
|
||||
|
||||
try {
|
||||
await invoke<void>('check_web_permission', {
|
||||
extensionId: extension.id,
|
||||
method,
|
||||
url,
|
||||
})
|
||||
|
||||
return { status: 'granted' }
|
||||
} catch (error: any) {
|
||||
// Permission denied errors return a specific error code
|
||||
if (error?.code === 1002 || error?.message?.includes('Permission denied')) {
|
||||
return { status: 'denied' }
|
||||
}
|
||||
// Other errors should be thrown
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async function checkDatabasePermissionAsync(
|
||||
params: Record<string, unknown>,
|
||||
extension: IHaexHubExtension,
|
||||
) {
|
||||
const resource = params.resource as string
|
||||
const operation = params.operation as string
|
||||
|
||||
if (!resource || !operation) {
|
||||
throw new Error('Resource and operation are required')
|
||||
}
|
||||
|
||||
try {
|
||||
await invoke<void>('check_database_permission', {
|
||||
extensionId: extension.id,
|
||||
resource,
|
||||
operation,
|
||||
})
|
||||
|
||||
return { status: 'granted' }
|
||||
} catch (error: any) {
|
||||
if (error?.code === 1002 || error?.message?.includes('Permission denied')) {
|
||||
return { status: 'denied' }
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async function checkFilesystemPermissionAsync(
|
||||
params: Record<string, unknown>,
|
||||
extension: IHaexHubExtension,
|
||||
) {
|
||||
const path = params.path as string
|
||||
const operation = params.operation as string
|
||||
|
||||
if (!path || !operation) {
|
||||
throw new Error('Path and operation are required')
|
||||
}
|
||||
|
||||
try {
|
||||
await invoke<void>('check_filesystem_permission', {
|
||||
extensionId: extension.id,
|
||||
path,
|
||||
operation,
|
||||
})
|
||||
|
||||
return { status: 'granted' }
|
||||
} catch (error: any) {
|
||||
if (error?.code === 1002 || error?.message?.includes('Permission denied')) {
|
||||
return { status: 'denied' }
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,11 +62,23 @@ async function handleWebFetchAsync(
|
||||
body: response.body,
|
||||
url: response.url,
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('Web request error:', error)
|
||||
|
||||
// Check if it's a permission denied error
|
||||
if (error?.code === 1002 || error?.message?.includes('Permission denied')) {
|
||||
const toast = useToast()
|
||||
toast.add({
|
||||
title: 'Permission denied',
|
||||
description: `Extension "${extension.name}" does not have permission to access ${url}`,
|
||||
color: 'error',
|
||||
})
|
||||
}
|
||||
|
||||
if (error instanceof Error) {
|
||||
throw new Error(`Web request failed: ${error.message}`)
|
||||
}
|
||||
throw new Error('Web request failed with unknown error')
|
||||
throw new Error(`Web request failed with unknown error: ${JSON.stringify(error)}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user