Skip to content

Commit

Permalink
added check connection api
Browse files Browse the repository at this point in the history
  • Loading branch information
mariotaku committed May 7, 2024
1 parent d182198 commit 30eb8b8
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 58 deletions.
1 change: 1 addition & 0 deletions src-tauri/build.rs
Expand Up @@ -14,6 +14,7 @@ fn main() {
"novacom_getkey",
"localkey_verify",
"privkey_read",
"check_connection",
]),
)
.plugin(
Expand Down
3 changes: 2 additions & 1 deletion src-tauri/permissions/device-manager/default.toml
Expand Up @@ -7,5 +7,6 @@ permissions = [
"allow-remove",
"allow-novacom-getkey",
"allow-localkey-verify",
"allow-privkey-read"
"allow-privkey-read",
"allow-check-connection"
]
104 changes: 55 additions & 49 deletions src-tauri/src/conn_pool/connection.rs
Expand Up @@ -15,59 +15,12 @@ use crate::error::Error;

impl DeviceConnection {
pub(crate) fn new(device: Device, ssh_dir: Option<&Path>) -> Result<DeviceConnection, Error> {
let kex = vec![
"curve25519-sha256",
"curve25519-sha256@libssh.org",
"ecdh-sha2-nistp256",
"ecdh-sha2-nistp384",
"ecdh-sha2-nistp521",
"diffie-hellman-group18-sha512",
"diffie-hellman-group16-sha512",
"diffie-hellman-group-exchange-sha256",
"diffie-hellman-group14-sha256",
"diffie-hellman-group1-sha1",
"diffie-hellman-group14-sha1",
];
let hmac = vec![
"hmac-sha2-256-etm@openssh.com",
"hmac-sha2-512-etm@openssh.com",
"hmac-sha2-256",
"hmac-sha2-512",
"hmac-sha1-96",
"hmac-sha1",
"hmac-md5",
];
let key_types = vec![
"ssh-ed25519",
"ecdsa-sha2-nistp521",
"ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp256",
"rsa-sha2-512",
"rsa-sha2-256",
"ssh-rsa",
];
let session = Session::new()?;
session.set_option(SshOption::Timeout(Duration::from_secs(10)))?;
Self::session_init(&session)?;

session.set_option(SshOption::Hostname(device.host.clone()))?;
session.set_option(SshOption::Port(device.port.clone()))?;
session.set_option(SshOption::User(Some(device.username.clone())))?;
session.set_option(SshOption::KeyExchange(kex.join(",")))?;
session.set_option(SshOption::HmacCS(hmac.join(",")))?;
session.set_option(SshOption::HmacSC(hmac.join(",")))?;
session.set_option(SshOption::HostKeys(key_types.join(",")))?;
session.set_option(SshOption::PublicKeyAcceptedTypes(key_types.join(",")))?;
session.set_option(SshOption::ProcessConfig(false))?;
#[cfg(windows)]
{
session.set_option(SshOption::KnownHosts(Some("C:\\nul".to_string())))?;
session.set_option(SshOption::GlobalKnownHosts(Some("C:\\nul".to_string())))?;
}

#[cfg(not(windows))]
{
session.set_option(SshOption::KnownHosts(Some(format!("/dev/null"))))?;
session.set_option(SshOption::GlobalKnownHosts(Some(format!("/dev/null"))))?;
}

session.connect()?;

Expand Down Expand Up @@ -116,6 +69,59 @@ impl DeviceConnection {
.lock()
.expect("Failed to lock DeviceConnection::last_ok") = true;
}

pub(crate) fn session_init(session: &Session) -> Result<(), Error> {
let kex = vec![
"curve25519-sha256",
"curve25519-sha256@libssh.org",
"ecdh-sha2-nistp256",
"ecdh-sha2-nistp384",
"ecdh-sha2-nistp521",
"diffie-hellman-group18-sha512",
"diffie-hellman-group16-sha512",
"diffie-hellman-group-exchange-sha256",
"diffie-hellman-group14-sha256",
"diffie-hellman-group1-sha1",
"diffie-hellman-group14-sha1",
];
let hmac = vec![
"hmac-sha2-256-etm@openssh.com",
"hmac-sha2-512-etm@openssh.com",
"hmac-sha2-256",
"hmac-sha2-512",
"hmac-sha1-96",
"hmac-sha1",
"hmac-md5",
];
let key_types = vec![
"ssh-ed25519",
"ecdsa-sha2-nistp521",
"ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp256",
"rsa-sha2-512",
"rsa-sha2-256",
"ssh-rsa",
];
session.set_option(SshOption::Timeout(Duration::from_secs(10)))?;
session.set_option(SshOption::KeyExchange(kex.join(",")))?;
session.set_option(SshOption::HmacCS(hmac.join(",")))?;
session.set_option(SshOption::HmacSC(hmac.join(",")))?;
session.set_option(SshOption::HostKeys(key_types.join(",")))?;
session.set_option(SshOption::PublicKeyAcceptedTypes(key_types.join(",")))?;
session.set_option(SshOption::ProcessConfig(false))?;
#[cfg(windows)]
{
session.set_option(SshOption::KnownHosts(Some("C:\\nul".to_string())))?;
session.set_option(SshOption::GlobalKnownHosts(Some("C:\\nul".to_string())))?;
}

#[cfg(not(windows))]
{
session.set_option(SshOption::KnownHosts(Some(format!("/dev/null"))))?;
session.set_option(SshOption::GlobalKnownHosts(Some(format!("/dev/null"))))?;
}
return Ok(());
}
}

impl Deref for DeviceConnection {
Expand Down
42 changes: 38 additions & 4 deletions src-tauri/src/device_manager/manager.rs
@@ -1,13 +1,15 @@
use std::fs;
use std::path::{Path, PathBuf};

use libssh_rs::SshKey;
use tokio::fs::{File, remove_file};
use libssh_rs::{Session, SshKey, SshResult};
use log::log;
use tokio::fs::{remove_file, File};
use tokio::io::AsyncWriteExt;

use crate::app_dirs::{GetConfDir, GetSshDir, SetConfDir, SetSshDir};
use crate::conn_pool::DeviceConnection;
use crate::device_manager::io::{read, write};
use crate::device_manager::{Device, DeviceManager, PrivateKey};
use crate::device_manager::{Device, DeviceCheckConnection, DeviceManager, PrivateKey};
use crate::error::Error;

impl DeviceManager {
Expand Down Expand Up @@ -98,7 +100,7 @@ impl DeviceManager {

//noinspection HttpUrlsUsage
pub async fn novacom_getkey(&self, address: &str, passphrase: &str) -> Result<String, Error> {
let resp = reqwest::get(format!("http://{}:9991/webos_rsa", address))
let resp = reqwest::get(format!("http://{address}:9991/webos_rsa"))
.await?
.error_for_status()?;
let content = resp.text().await?;
Expand Down Expand Up @@ -129,6 +131,38 @@ impl DeviceManager {
}),
};
}

pub async fn check_connection(&self, host: &str) -> Result<DeviceCheckConnection, Error> {
async fn ssh_probe(host: &str, port: u16, user: &str) -> Result<String, Error> {
let host = host.to_string();
let user = user.to_string();
return tokio::task::spawn_blocking(move || {
let ssh_sess = Session::new()?;
DeviceConnection::session_init(&ssh_sess)?;
ssh_sess.set_option(libssh_rs::SshOption::Hostname(host))?;
ssh_sess.set_option(libssh_rs::SshOption::Port(port))?;
ssh_sess.set_option(libssh_rs::SshOption::User(Some(user)))?;
ssh_sess.connect()?;
return Ok(ssh_sess.get_server_banner()?);
})
.await
.expect("Failed to spawn_blocking");
}
//noinspection HttpUrlsUsage
async fn key_server_probe(host: &str) -> Result<String, Error> {
return reqwest::get(format!("http://{host}:9991/webos_rsa"))
.await?
.error_for_status()?
.text()
.await
.map_err(Error::from);
}
return Ok(DeviceCheckConnection {
ssh_22: ssh_probe(host, 22, "root").await.ok(),
ssh_9922: ssh_probe(host, 9922, "prisoner").await.ok(),
key_server: key_server_probe(host).await.is_ok(),
});
}
}

impl GetSshDir for DeviceManager {
Expand Down
14 changes: 11 additions & 3 deletions src-tauri/src/device_manager/mod.rs
Expand Up @@ -60,9 +60,9 @@ pub struct Device {
#[serde(rename = "logDaemon", skip_serializing_if = "Option::is_none")]
pub log_daemon: Option<String>,
#[serde(
rename = "noPortForwarding",
default,
skip_serializing_if = "Option::is_none"
rename = "noPortForwarding",
default,
skip_serializing_if = "Option::is_none"
)]
pub no_port_forwarding: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
Expand All @@ -76,3 +76,11 @@ pub enum DeviceFileTransfer {
#[serde(rename = "sftp")]
Sftp,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DeviceCheckConnection {
pub ssh_22: Option<String>,
pub ssh_9922: Option<String>,
pub key_server: bool,
}
8 changes: 7 additions & 1 deletion src-tauri/src/plugins/device.rs
Expand Up @@ -4,7 +4,7 @@ use tauri::{
Runtime,
};

use crate::device_manager::{Device, DeviceManager};
use crate::device_manager::{Device, DeviceCheckConnection, DeviceManager};
use crate::error::Error;
use crate::app_dirs::GetSshDir;

Expand Down Expand Up @@ -65,6 +65,11 @@ async fn privkey_read<R: Runtime>(app: AppHandle<R>, device: Device) -> Result<S
.content(app.get_ssh_dir().as_deref())?);
}

#[tauri::command]
async fn check_connection(manager: State<'_, DeviceManager>, host: String) -> Result<DeviceCheckConnection, Error> {
return manager.check_connection(&host).await;
}

/// Initializes the plugin.
pub fn plugin<R: Runtime>(name: &'static str) -> TauriPlugin<R> {
Builder::new(name)
Expand All @@ -76,6 +81,7 @@ pub fn plugin<R: Runtime>(name: &'static str) -> TauriPlugin<R> {
novacom_getkey,
localkey_verify,
privkey_read,
check_connection,
])
.build()
}
10 changes: 10 additions & 0 deletions src/app/core/services/device-manager.service.ts
Expand Up @@ -69,6 +69,10 @@ export class DeviceManagerService extends BackendClient {
await this.invoke('localkey_verify', {name, passphrase});
}

async checkConnection(host: string): Promise<DeviceCheckConnection> {
return await this.invoke('check_connection', {host});
}

async listCrashReports(device: Device): Promise<CrashReport[]> {
const dirs = [
'/tmp/faultmanager/crash/',
Expand Down Expand Up @@ -236,3 +240,9 @@ export interface DeviceInfo {
firmwareVersion: string;
socName?: string;
}

export declare interface DeviceCheckConnection {
keyServer: boolean;
ssh22?: string;
ssh9922?: string;
}

0 comments on commit 30eb8b8

Please sign in to comment.