audb_core/features/device/
add.rs1use crate::features::config::device_store::DeviceStore;
2use crate::tools::macros::print_info;
3use crate::tools::ssh::SshClient;
4use crate::tools::types::{Device, Platform};
5use crate::tools::validation::{validate_ip_address, validate_port, validate_ssh_key_exists};
6use anyhow::{anyhow, Result};
7use dialoguer::{Confirm, Input, Password, Select};
8use std::path::PathBuf;
9
10pub async fn execute() -> Result<()> {
11 println!("\x1b[1m\x1b[36mAdd Aurora OS Device\x1b[0m\n");
12
13 let name: String = Input::new()
15 .with_prompt("Device name (optional, press Enter to skip)")
16 .allow_empty(true)
17 .interact_text()?;
18
19 let name = if name.trim().is_empty() {
20 None
21 } else {
22 Some(name.trim().to_string())
23 };
24
25 let host: String = Input::new()
27 .with_prompt("Host IP address")
28 .validate_with(|input: &String| -> Result<(), &str> {
29 if validate_ip_address(input).is_ok() {
30 Ok(())
31 } else {
32 Err("Invalid IP address format")
33 }
34 })
35 .interact_text()?;
36
37 let port: u16 = Input::new()
39 .with_prompt("SSH port")
40 .default(22)
41 .validate_with(|input: &u16| -> Result<(), &str> {
42 if validate_port(*input).is_ok() {
43 Ok(())
44 } else {
45 Err("Port cannot be 0")
46 }
47 })
48 .interact_text()?;
49
50 let default_key = shellexpand::tilde("~/.ssh/id_rsa").to_string();
52 let auth: String = Input::new()
53 .with_prompt("SSH private key path")
54 .default(default_key)
55 .validate_with(|input: &String| -> Result<(), &str> {
56 let path = PathBuf::from(shellexpand::tilde(input).to_string());
57 if validate_ssh_key_exists(&path).is_ok() {
58 Ok(())
59 } else {
60 Err("SSH key file does not exist")
61 }
62 })
63 .interact_text()?;
64
65 let root_password: String = Password::new()
67 .with_prompt("Root password (for devel-su automation - tap/swipe/screenshot)")
68 .allow_empty_password(true)
69 .interact()?;
70
71 let platforms = vec!["aurora-arm", "aurora-arm64"];
73 let selection = Select::new()
74 .with_prompt("Platform")
75 .items(&platforms)
76 .default(0)
77 .interact()?;
78
79 let platform = match selection {
80 0 => Platform::AuroraArm,
81 1 => Platform::AuroraArm64,
82 _ => return Err(anyhow!("Invalid platform selection")),
83 };
84
85 let device = Device {
87 name,
88 host: host.clone(),
89 port,
90 auth: auth.clone(),
91 root_password: root_password.clone(),
92 platform,
93 enabled: true,
94 };
95
96 print_info("Testing SSH connection as defaultuser...");
98 let key_path = device.auth_path();
99 let connection_ok = SshClient::test_connection(&host, port, &key_path);
100
101 if !connection_ok {
102 println!("\x1b[1m\x1b[93mwarning\x1b[0m: Could not establish SSH connection to the device");
103
104 let add_anyway = Confirm::new()
105 .with_prompt("Add device anyway?")
106 .default(false)
107 .interact()?;
108
109 if !add_anyway {
110 return Err(anyhow!("Device not added"));
111 }
112 } else {
113 println!("\x1b[1m\x1b[32msuccess\x1b[0m: defaultuser SSH connection verified");
114 }
115
116 DeviceStore::add(device)?;
118
119 println!("\n\x1b[1m\x1b[32msuccess\x1b[0m: Device added successfully");
120 if root_password.is_empty() {
121 println!("\x1b[1m\x1b[90mnote\x1b[0m: Tap/swipe/screenshot commands require root password to be configured");
122 }
123 Ok(())
124}