Provisioning halfway :P

This commit is contained in:
litoral05
2026-05-08 17:30:08 +01:00
parent 8075104243
commit ec2727927b
5 changed files with 659 additions and 215 deletions
+200 -5
View File
@@ -1,16 +1,211 @@
use std::process::Command;
#[tauri::command]
pub async fn remove_known_host(
ip: String,
) -> Result<String, String> {
if ip.trim().is_empty() {
return Err(
"ip address cannot be empty"
.into(),
"ip address cannot be empty".into(),
);
}
Ok(format!(
"removed stale known_hosts entry for {}",
ip,
let output = Command::new("ssh-keygen")
.args(["-R", &ip])
.output()
.map_err(|error| {
format!(
"failed to run ssh-keygen: {}",
error,
)
})?;
if output.status.success() {
Ok(format!(
"removed stale known_hosts entry for {}",
ip,
))
} else {
Err(String::from_utf8_lossy(&output.stderr)
.to_string())
}
}
#[tauri::command]
pub async fn probe_router_ssh(
ip: String,
) -> Result<String, String> {
if ip.trim().is_empty() {
return Err(
"router IP is required".into(),
);
}
let output = Command::new("ssh")
.args([
"-o",
"BatchMode=yes",
"-o",
"ConnectTimeout=5",
"-o",
"StrictHostKeyChecking=accept-new",
&format!("root@{}", ip),
"ubus call system board",
])
.output()
.map_err(|error| {
format!(
"failed to run ssh command: {}",
error,
)
})?;
let stdout =
String::from_utf8_lossy(&output.stdout)
.to_string();
let stderr =
String::from_utf8_lossy(&output.stderr)
.to_string();
if output.status.success() {
return Ok(stdout);
}
if stderr.contains(
"REMOTE HOST IDENTIFICATION HAS CHANGED",
) {
return Err(format!(
"STALE_HOST_KEY: SSH host key mismatch for {}. Remove known_hosts entry and retry.",
ip,
));
}
if stderr.contains("Permission denied")
|| stderr.contains("publickey")
|| stderr.contains("password")
{
return Err(format!(
"AUTH_REQUIRED: Router is reachable at {}, but SSH requires password login. Try manually: ssh root@{} then run: ubus call system board",
ip, ip,
));
}
Err(format!(
"SSH_FAILED: {}\n{}",
stderr, stdout,
))
}
use ssh2::Session;
use std::{
io::Read,
net::{TcpStream, ToSocketAddrs},
time::Duration,
};
#[tauri::command]
pub async fn inspect_router_with_password(
ip: String,
password: String,
) -> Result<String, String> {
if ip.trim().is_empty() {
return Err("router IP is required".into());
}
if password.trim().is_empty() {
return Err("router password is required".into());
}
let address = format!("{}:22", ip);
let socket_address = address
.to_socket_addrs()
.map_err(|error| {
format!("failed to resolve router address: {}", error)
})?
.next()
.ok_or_else(|| {
format!("failed to resolve router address {}", address)
})?;
let tcp = TcpStream::connect_timeout(
&socket_address,
Duration::from_secs(5),
)
.map_err(|error| {
format!("failed to connect to SSH on {}: {}", ip, error)
})?;
tcp.set_read_timeout(Some(Duration::from_secs(10)))
.map_err(|error| {
format!("failed to set SSH read timeout: {}", error)
})?;
tcp.set_write_timeout(Some(Duration::from_secs(10)))
.map_err(|error| {
format!("failed to set SSH write timeout: {}", error)
})?;
let mut session = Session::new()
.map_err(|error| {
format!("failed to create SSH session: {}", error)
})?;
session.set_tcp_stream(tcp);
session.handshake().map_err(|error| {
format!("SSH handshake failed for {}: {}", ip, error)
})?;
session
.userauth_password("root", &password)
.map_err(|error| {
format!(
"SSH authentication failed for root@{}: {}",
ip, error
)
})?;
if !session.authenticated() {
return Err(format!(
"SSH authentication failed for root@{}",
ip
));
}
let mut channel = session.channel_session().map_err(|error| {
format!("failed to open SSH channel: {}", error)
})?;
channel
.exec("ubus call system board")
.map_err(|error| {
format!("failed to run router inspection command: {}", error)
})?;
let mut stdout = String::new();
channel
.read_to_string(&mut stdout)
.map_err(|error| {
format!("failed to read router inspection output: {}", error)
})?;
channel.wait_close().map_err(|error| {
format!("failed to close SSH channel: {}", error)
})?;
let exit_status = channel.exit_status().map_err(|error| {
format!("failed to read SSH command exit status: {}", error)
})?;
if exit_status != 0 {
return Err(format!(
"router inspection command failed with exit code {}",
exit_status
));
}
Ok(stdout)
}
+7 -1
View File
@@ -13,7 +13,11 @@ use commands::{
verify_router,
wait_for_ssh,
},
ssh::remove_known_host,
ssh::{
inspect_router_with_password,
probe_router_ssh,
remove_known_host,
},
};
#[cfg_attr(mobile, tauri::mobile_entry_point)]
@@ -25,6 +29,8 @@ pub fn run() {
read_text_file,
ping_host,
remove_known_host,
probe_router_ssh,
inspect_router_with_password,
detect_router,
upload_firmware,
flash_router,