Loading...
Loading...
Teaches the assistant about Tauri IPC (Inter-Process Communication) patterns including brownfield and isolation approaches for secure message passing between frontend and Rust backend.
npx skill4agent add dchuk/claude-code-tauri-skills understanding-tauri-ipcuse tauri::{AppHandle, Emitter};
fn emit_event(app: &AppHandle) {
app.emit("backend-event", "payload data").unwrap();
}import { listen } from '@tauri-apps/api/event';
const unlisten = await listen('backend-event', (event) => {
console.log('Received:', event.payload);
});
// Call unlisten() when doneimport { emit } from '@tauri-apps/api/event';
await emit('frontend-event', { data: 'value' });fetch()#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}import { invoke } from '@tauri-apps/api/core';
const greeting = await invoke('greet', { name: 'World' });
console.log(greeting); // "Hello, World!"#[tauri::command]
async fn read_file(path: String) -> Result<String, String> {
std::fs::read_to_string(&path)
.map_err(|e| e.to_string())
}{
"app": {
"security": {
"pattern": {
"use": "brownfield"
}
}
}
}#[tauri::command]
fn process_data(input: String) -> Result<String, String> {
// Direct processing without isolation layer
Ok(format!("Processed: {}", input))
}import { invoke } from '@tauri-apps/api/core';
// Direct invocation - no isolation layer
const result = await invoke('process_data', { input: 'test' });{
"app": {
"security": {
"pattern": {
"use": "isolation",
"options": {
"dir": "../dist-isolation"
}
}
}
}
}project/
src/ # Main frontend
src-tauri/ # Rust backend
dist-isolation/
index.html
index.js<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Isolation Secure Script</title>
</head>
<body>
<script src="index.js"></script>
</body>
</html>window.__TAURI_ISOLATION_HOOK__ = (payload) => {
// Log all IPC calls for debugging
console.log('IPC call intercepted:', payload);
// Return payload unchanged (passthrough)
return payload;
};window.__TAURI_ISOLATION_HOOK__ = (payload) => {
// Validate command calls
if (payload.cmd === 'invoke') {
const { __tauriModule, message } = payload;
// Block unauthorized file system access
if (message.cmd === 'readFile') {
const path = message.path;
if (!path.startsWith('/allowed/directory/')) {
console.error('Blocked unauthorized file access:', path);
return null; // Block the request
}
}
// Validate specific commands
if (message.cmd === 'deleteItem') {
if (!confirm('Are you sure you want to delete this item?')) {
return null; // User cancelled
}
}
}
return payload;
};const ALLOWED_COMMANDS = ['greet', 'read_config', 'save_settings'];
const BLOCKED_PATHS = ['/etc/', '/usr/', '/System/'];
window.__TAURI_ISOLATION_HOOK__ = (payload) => {
// Validate invoke commands
if (payload.cmd === 'invoke') {
const commandName = payload.message?.cmd;
// Whitelist approach
if (!ALLOWED_COMMANDS.includes(commandName)) {
console.warn('Blocked unknown command:', commandName);
return null;
}
// Validate path arguments
const args = payload.message?.args || {};
if (args.path) {
for (const blocked of BLOCKED_PATHS) {
if (args.path.startsWith(blocked)) {
console.error('Blocked access to protected path:', args.path);
return null;
}
}
}
}
// Validate event emissions
if (payload.cmd === 'emit') {
const eventName = payload.event;
// Add event validation as needed
}
return payload;
};| Aspect | Brownfield | Isolation |
|---|---|---|
| Default | Yes | No |
| Configuration | None required | Requires isolation app |
| Security | Basic | Enhanced |
| Validation | Command-level only | All IPC calls |
| Encryption | None | AES-GCM |
| Performance | Fastest | Slight overhead |
| Complexity | Simple | Moderate |
| Best for | Trusted code, prototypes | Production, sensitive apps |
#[tauri::command]
fn process_file(path: String) -> Result<String, String> {
// Always validate paths
if path.contains("..") || path.starts_with("/etc") {
return Err("Invalid path".into());
}
// Process file...
Ok("Done".into())
}#[derive(serde::Deserialize)]
struct CreateUserArgs {
name: String,
email: String,
}
#[tauri::command]
fn create_user(args: CreateUserArgs) -> Result<(), String> {
// Type-safe argument handling
Ok(())
}capabilities/