Skip to content

Commit 6d6b1f0

Browse files
T3pp31claude
andcommitted
feat: graceful Npcap handling - show download dialog when not installed
- Add /DELAYLOAD:wpcap.dll to prevent app crash when Npcap is missing - Add runtime Npcap check via LoadLibraryA on Windows - Guard pcap-dependent commands (lan_scan, start_arp_spoof) with Npcap check - Add NpcapDialog component to prompt users to download Npcap - Add useNpcapCheck hook for frontend Npcap availability checking - Add tauri-plugin-shell for opening external URLs in browser - Add tests for NpcapDialog, useNpcapCheck, and npcap defaults Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 20139fc commit 6d6b1f0

25 files changed

Lines changed: 1708 additions & 20 deletions

package-lock.json

Lines changed: 894 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@
1313
"@tauri-apps/api": "^2.10.1",
1414
"@tauri-apps/plugin-dialog": "^2.6.0",
1515
"@tauri-apps/plugin-fs": "^2.4.5",
16+
"@tauri-apps/plugin-shell": "^2.3.5",
1617
"react": "^18.3.1",
1718
"react-dom": "^18.3.1",
1819
"react-router-dom": "^7.13.1"
1920
},
2021
"devDependencies": {
2122
"@eslint/js": "^9.13.0",
23+
"@testing-library/jest-dom": "^6.9.1",
24+
"@testing-library/react": "^16.3.2",
2225
"@types/react": "^18.3.12",
2326
"@types/react-dom": "^18.3.1",
2427
"@vitejs/plugin-react": "^4.3.3",
@@ -27,6 +30,7 @@
2730
"eslint-plugin-react-hooks": "^5.0.0",
2831
"eslint-plugin-react-refresh": "^0.4.14",
2932
"globals": "^15.11.0",
33+
"happy-dom": "^20.8.4",
3034
"typescript": "~5.6.2",
3135
"typescript-eslint": "^8.11.0",
3236
"vite": "^5.4.10",

src-tauri/Cargo.lock

Lines changed: 101 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ tauri-build = { version = "2", features = [] }
1919
tauri = { version = "2", features = [] }
2020
tauri-plugin-dialog = "2"
2121
tauri-plugin-fs = "2"
22+
tauri-plugin-shell = "2"
2223
serde = { version = "1", features = ["derive"] }
2324
serde_json = "1"
2425
tokio = { version = "1", features = ["full"] }

src-tauri/build.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,19 @@ fn configure_npcap_link_search() {
8989
#[cfg(not(target_os = "windows"))]
9090
fn configure_npcap_link_search() {}
9191

92+
/// Windows: wpcap.dll を遅延ロードに設定し、未インストール時もアプリが起動できるようにする
93+
#[cfg(target_os = "windows")]
94+
fn configure_delay_load() {
95+
println!("cargo:rustc-link-arg=/DELAYLOAD:wpcap.dll");
96+
println!("cargo:rustc-link-lib=delayimp");
97+
}
98+
99+
/// Linux / macOS では遅延ロード設定は不要
100+
#[cfg(not(target_os = "windows"))]
101+
fn configure_delay_load() {}
102+
92103
fn main() {
93104
configure_npcap_link_search();
105+
configure_delay_load();
94106
tauri_build::build();
95107
}

src-tauri/src/commands/arp_spoof.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use serde::Serialize;
22

3+
use crate::config::NPCAP_DOWNLOAD_URL;
34
use crate::error::AppError;
45
use crate::AppState;
56

@@ -17,6 +18,9 @@ pub async fn start_arp_spoof(
1718
packet_count: u32,
1819
state: tauri::State<'_, AppState>,
1920
) -> Result<String, AppError> {
21+
if !crate::network::npcap::is_npcap_available() {
22+
return Err(AppError::NpcapNotFound(NPCAP_DOWNLOAD_URL.to_string()));
23+
}
2024
crate::network::arp_spoof::start(
2125
&target_ip,
2226
&gateway_ip,

src-tauri/src/commands/lan_scan.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use serde::Serialize;
22
use tauri::Window;
33

4+
use crate::config::NPCAP_DOWNLOAD_URL;
45
use crate::error::AppError;
56
use crate::AppState;
67

@@ -19,5 +20,8 @@ pub async fn lan_scan(
1920
state: tauri::State<'_, AppState>,
2021
window: Window,
2122
) -> Result<Vec<DeviceInfo>, AppError> {
23+
if !crate::network::npcap::is_npcap_available() {
24+
return Err(AppError::NpcapNotFound(NPCAP_DOWNLOAD_URL.to_string()));
25+
}
2226
crate::network::lan_scan::scan(start, end, &state.config, &state.http_client, &window).await
2327
}

src-tauri/src/commands/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ pub mod arp_spoof;
22
pub mod binary;
33
pub mod lan_scan;
44
pub mod network_info;
5+
pub mod npcap;
56
pub mod port_scan;

src-tauri/src/commands/npcap.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use serde::Serialize;
2+
3+
use crate::config::NPCAP_DOWNLOAD_URL;
4+
5+
#[derive(Debug, Serialize)]
6+
pub struct NpcapStatus {
7+
pub available: bool,
8+
pub download_url: String,
9+
}
10+
11+
#[tauri::command]
12+
pub async fn check_npcap() -> NpcapStatus {
13+
NpcapStatus {
14+
available: crate::network::npcap::is_npcap_available(),
15+
download_url: NPCAP_DOWNLOAD_URL.to_string(),
16+
}
17+
}

src-tauri/src/config.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use serde::Deserialize;
22
use std::path::PathBuf;
33

4+
/// Npcap ダウンロードページの URL
5+
pub const NPCAP_DOWNLOAD_URL: &str = "https://npcap.com/#download";
6+
47
#[derive(Debug, Deserialize, Clone)]
58
pub struct AppConfig {
69
pub scan: ScanConfig,

0 commit comments

Comments
 (0)