diff --git a/adb_client/Cargo.toml b/adb_client/Cargo.toml index 197bb7e..be9e348 100644 --- a/adb_client/Cargo.toml +++ b/adb_client/Cargo.toml @@ -18,26 +18,26 @@ rustdoc-args = ["--cfg", "docsrs"] default = [] mdns = ["dep:mdns-sd"] rusb = ["dep:rsa", "dep:rusb"] +webusb = ["dep:webusb-web", "dep:rsa"] [dependencies] base64 = { version = "0.22.1" } bincode = { version = "1.3.3" } byteorder = { version = "1.5.0" } chrono = { version = "0.4.42", default-features = false, features = ["std"] } -homedir = { version = "=0.3.4" } image = { version = "0.25.8", default-features = false } log = { version = "0.4.28" } num-bigint = { version = "0.8.4", package = "num-bigint-dig" } num-traits = { version = "0.2.19" } quick-protobuf = { version = "0.8.1" } -rand = { version = "0.9.2" } +rand = { version = "0.8.5" } rcgen = { version = "0.13.2", default-features = false, features = [ - "aws_lc_rs", "pem", + "ring" ] } regex = { version = "1.12.2", features = ["perf", "std", "unicode"] } -rustls = { version = "0.23.33" } -rustls-pki-types = { version = "1.12.0" } +rustls = { version = "0.23.33", default-features = false, features = ["logging", "ring", "std", "tls12"] } +rustls-pki-types = { version = "1.12.0", features = ["web"] } serde = { version = "1.0.228", features = ["derive"] } serde_repr = { version = "0.1.20" } sha1 = { version = "0.10.6", features = ["oid"] } @@ -54,6 +54,12 @@ mdns-sd = { version = "0.13.11", default-features = false, features = [ rsa = { version = "0.9.7", optional = true } rusb = { version = "0.9.4", features = ["vendored"], optional = true } ######### +######### +# webusb dependencies +webusb-web = { version = "0.4.1", optional = true } +getrandom = { version = "0.2.16", features = ["js"] } +ring = { version = "0.17.14", features = ["wasm32_unknown_unknown_js"] } + [dev-dependencies] anyhow = { version = "1.0.100" } diff --git a/adb_client/src/adb_device_ext.rs b/adb_client/src/adb_device_ext.rs index 962ccaa..1eeb8f4 100644 --- a/adb_client/src/adb_device_ext.rs +++ b/adb_client/src/adb_device_ext.rs @@ -8,7 +8,7 @@ use crate::{RebootType, Result}; /// Trait representing all features available on an ADB device, currently used by: /// - [`crate::server_device::ADBServerDevice`] -/// - [`crate::usb::ADBUSBDevice`] +/// - [`crate::usb::ADBRusbDevice`] /// - [`crate::tcp::ADBTcpDevice`] pub trait ADBDeviceExt { /// Runs command in a shell on the device, and write its output and error streams into output. diff --git a/adb_client/src/emulator/tcp_emulator_transport.rs b/adb_client/src/emulator/tcp_emulator_transport.rs index 7572d04..2ee05ab 100644 --- a/adb_client/src/emulator/tcp_emulator_transport.rs +++ b/adb_client/src/emulator/tcp_emulator_transport.rs @@ -4,8 +4,6 @@ use std::{ net::{SocketAddrV4, TcpStream}, }; -use homedir::my_home; - use crate::{ Result, RustADBError, adb_transport::ADBTransport, emulator::models::ADBEmulatorCommand, }; @@ -37,7 +35,7 @@ impl TCPEmulatorTransport { /// Return authentication token stored in `$HOME/.emulator_console_auth_token` pub fn get_authentication_token(&mut self) -> Result { - let Some(home) = my_home()? else { + let Some(home) = std::env::home_dir() else { return Err(RustADBError::NoHomeDirectory); }; diff --git a/adb_client/src/error.rs b/adb_client/src/error.rs index ba650ef..fe34bba 100644 --- a/adb_client/src/error.rs +++ b/adb_client/src/error.rs @@ -63,9 +63,6 @@ pub enum RustADBError { /// Unimplemented framebuffer image version #[error("Unimplemented framebuffer image version: {0}")] UnimplementedFramebufferImageVersion(u32), - /// An error occurred while getting user's home directory - #[error(transparent)] - HomeError(#[from] homedir::GetHomeError), /// Cannot get home directory #[error("Cannot get home directory")] NoHomeDirectory, @@ -90,8 +87,8 @@ pub enum RustADBError { #[error(transparent)] Base64EncodeError(#[from] base64::EncodeSliceError), /// An error occurred with RSA engine - #[cfg(feature = "rusb")] - #[cfg_attr(docsrs, doc(cfg(feature = "rusb")))] + #[cfg(any(feature = "rusb", feature = "webusb"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "rusb", feature = "webusb"))))] #[error(transparent)] RSAError(#[from] rsa::errors::Error), /// Cannot convert given data from slice @@ -101,8 +98,8 @@ pub enum RustADBError { #[error("wrong file extension: {0}")] WrongFileExtension(String), /// An error occurred with PKCS8 data - #[cfg(feature = "rusb")] - #[cfg_attr(docsrs, doc(cfg(feature = "rusb")))] + #[cfg(any(feature = "rusb", feature = "webusb"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "rusb", feature = "webusb"))))] #[error("error with pkcs8: {0}")] RsaPkcs8Error(#[from] rsa::pkcs8::Error), /// Error during certificate generation diff --git a/adb_client/src/message_devices/adb_message_device.rs b/adb_client/src/message_devices/adb_message_device.rs index da0932d..c281460 100644 --- a/adb_client/src/message_devices/adb_message_device.rs +++ b/adb_client/src/message_devices/adb_message_device.rs @@ -1,5 +1,4 @@ use byteorder::{LittleEndian, ReadBytesExt}; -use rand::Rng; use std::io::{Cursor, Read, Seek}; use crate::{ @@ -219,11 +218,9 @@ impl ADBMessageDevice { } pub(crate) fn open_session(&mut self, data: &[u8]) -> Result { - let mut rng = rand::rng(); - let message = ADBTransportMessage::new( MessageCommand::Open, - rng.random(), // Our 'local-id' + rand::random::(), // Our 'local-id' 0, data, ); diff --git a/adb_client/src/message_devices/usb/adb_rusb_device.rs b/adb_client/src/message_devices/usb/adb_rusb_device.rs index 40e2737..fb99b28 100644 --- a/adb_client/src/message_devices/usb/adb_rusb_device.rs +++ b/adb_client/src/message_devices/usb/adb_rusb_device.rs @@ -16,7 +16,7 @@ pub struct ADBRusbDevice { } impl ADBRusbDevice { - /// Instantiate a new [`ADBRusb`] + /// Instantiate a new [`ADBRusbDevice`] pub fn new(vendor_id: u16, product_id: u16) -> Result { Self::new_with_custom_private_key(vendor_id, product_id, get_default_adb_key_path()?) } diff --git a/adb_client/src/message_devices/usb/adb_webusb_device.rs b/adb_client/src/message_devices/usb/adb_webusb_device.rs new file mode 100644 index 0000000..a290370 --- /dev/null +++ b/adb_client/src/message_devices/usb/adb_webusb_device.rs @@ -0,0 +1,69 @@ +use std::{ + io::{Read, Write}, + path::Path, +}; + +use crate::{ + ADBDeviceExt, Result, + usb::{WebUsbTransport, adb_usb_device::ADBUSBDevice}, +}; + +/// Implement Android USB device reachable over wired USB +#[derive(Debug)] +pub struct ADBWebUsbDevice { + inner: ADBUSBDevice, +} + +impl ADBWebUsbDevice { + /// Instantiate a new [`ADBRusb`] + pub fn new(_vendor_id: u16, _product_id: u16) -> Result { + todo!() + } +} + +impl ADBDeviceExt for ADBWebUsbDevice { + #[inline] + fn shell_command(&mut self, command: &[&str], output: &mut dyn Write) -> Result<()> { + self.inner.shell_command(command, output) + } + + #[inline] + fn shell<'a>(&mut self, reader: &mut dyn Read, writer: Box) -> Result<()> { + self.inner.shell(reader, writer) + } + + #[inline] + fn stat(&mut self, remote_path: &str) -> Result { + self.inner.stat(remote_path) + } + + #[inline] + fn pull(&mut self, source: &dyn AsRef, output: &mut dyn Write) -> Result<()> { + self.inner.pull(source, output) + } + + #[inline] + fn push(&mut self, stream: &mut dyn Read, path: &dyn AsRef) -> Result<()> { + self.inner.push(stream, path) + } + + #[inline] + fn reboot(&mut self, reboot_type: crate::RebootType) -> Result<()> { + self.inner.reboot(reboot_type) + } + + #[inline] + fn install(&mut self, apk_path: &dyn AsRef) -> Result<()> { + self.inner.install(apk_path) + } + + #[inline] + fn uninstall(&mut self, package: &str) -> Result<()> { + self.inner.uninstall(package) + } + + #[inline] + fn framebuffer_inner(&mut self) -> Result, Vec>> { + self.inner.framebuffer_inner() + } +} diff --git a/adb_client/src/message_devices/usb/backends/mod.rs b/adb_client/src/message_devices/usb/backends/mod.rs index 11c0af5..57d40bb 100644 --- a/adb_client/src/message_devices/usb/backends/mod.rs +++ b/adb_client/src/message_devices/usb/backends/mod.rs @@ -1,3 +1,7 @@ #[cfg(feature = "rusb")] #[cfg_attr(docsrs, doc(cfg(feature = "rusb")))] pub mod rusb_transport; + +#[cfg(feature = "webusb")] +#[cfg_attr(docsrs, doc(cfg(feature = "webusb")))] +pub mod webusb_transport; diff --git a/adb_client/src/message_devices/usb/backends/webusb_transport.rs b/adb_client/src/message_devices/usb/backends/webusb_transport.rs new file mode 100644 index 0000000..0e87cb8 --- /dev/null +++ b/adb_client/src/message_devices/usb/backends/webusb_transport.rs @@ -0,0 +1,48 @@ +use std::time::Duration; + +use crate::{ + Result, + adb_transport::ADBTransport, + message_devices::{ + adb_message_transport::ADBMessageTransport, adb_transport_message::ADBTransportMessage, + }, +}; + +/// Transport running on USB using `webusb` as a backend. +#[derive(Clone, Debug)] +pub struct WebUsbTransport {} + +impl WebUsbTransport { + /// Instantiate a new [`WebUsbTransport`]. + /// Only the first device with given vendor_id and product_id is returned. + pub fn new() -> Self { + WebUsbTransport {} + } +} + +impl ADBTransport for WebUsbTransport { + fn connect(&mut self) -> crate::Result<()> { + todo!() + } + + fn disconnect(&mut self) -> crate::Result<()> { + todo!() + } +} + +impl ADBMessageTransport for WebUsbTransport { + fn read_message_with_timeout( + &mut self, + _read_timeout: Duration, + ) -> Result { + todo!() + } + + fn write_message_with_timeout( + &mut self, + message: ADBTransportMessage, + write_timeout: std::time::Duration, + ) -> Result<()> { + todo!() + } +} diff --git a/adb_client/src/message_devices/usb/mod.rs b/adb_client/src/message_devices/usb/mod.rs index 677973b..8ec2a13 100644 --- a/adb_client/src/message_devices/usb/mod.rs +++ b/adb_client/src/message_devices/usb/mod.rs @@ -30,18 +30,11 @@ pub mod constants { } } -#[cfg(feature = "rusb")] -mod adb_rsa_key; - +// ################################################### +// rusb specific modules #[cfg(feature = "rusb")] mod adb_rusb_device; -#[cfg(feature = "rusb")] -mod adb_usb_device; - -mod backends; -mod utils; - // Device implementations #[cfg(feature = "rusb")] #[cfg_attr(docsrs, doc(cfg(feature = "rusb")))] @@ -51,10 +44,36 @@ pub use adb_rusb_device::ADBRusbDevice; #[cfg(feature = "rusb")] #[cfg_attr(docsrs, doc(cfg(feature = "rusb")))] pub use backends::rusb_transport::RusbTransport; +// ################################################### + +// ################################################### +// webusb specific modules +#[cfg(feature = "webusb")] +mod adb_webusb_device; + +// Device implementations +#[cfg(feature = "webusb")] +#[cfg_attr(docsrs, doc(cfg(feature = "webusb")))] +pub use adb_webusb_device::ADBWebUsbDevice; + +// Transport implementations +#[cfg(feature = "webusb")] +#[cfg_attr(docsrs, doc(cfg(feature = "webusb")))] +pub use backends::webusb_transport::WebUsbTransport; +// ################################################### + +mod backends; +mod utils; + +#[cfg(any(feature = "rusb", feature = "webusb"))] +mod adb_rsa_key; + +#[cfg(any(feature = "rusb", feature = "webusb"))] +mod adb_usb_device; // Utility functions -#[cfg(feature = "rusb")] -#[cfg_attr(docsrs, doc(cfg(feature = "rusb")))] +#[cfg(any(feature = "rusb", feature = "webusb"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "rusb", feature = "webusb"))))] pub use utils::read_adb_private_key; #[cfg(feature = "rusb")] diff --git a/adb_client/src/message_devices/usb/utils.rs b/adb_client/src/message_devices/usb/utils.rs index b54f35a..0eec3b8 100644 --- a/adb_client/src/message_devices/usb/utils.rs +++ b/adb_client/src/message_devices/usb/utils.rs @@ -4,7 +4,6 @@ use crate::{Result, RustADBError}; use std::fs::read_to_string; use std::path::Path; -#[cfg(feature = "rusb")] use crate::usb::adb_rsa_key::ADBRsaKey; #[cfg(feature = "rusb")] @@ -21,7 +20,6 @@ use crate::usb::constants::class_codes::{ /// /// Returns `Ok(None)` if the file doesn't exist, `Ok(Some(key))` if the key was successfully loaded, /// or an error if there was a problem reading the file. -#[cfg(feature = "rusb")] pub fn read_adb_private_key>(private_key_path: P) -> Result> { // Try to read the private key file from given path // If the file is not found, return None diff --git a/adb_client/src/utils.rs b/adb_client/src/utils.rs index 4b58dea..93c8d48 100644 --- a/adb_client/src/utils.rs +++ b/adb_client/src/utils.rs @@ -21,9 +21,7 @@ pub fn check_extension_is_apk>(path: P) -> Result<()> { } pub fn get_default_adb_key_path() -> Result { - homedir::my_home() - .ok() - .flatten() + std::env::home_dir() .map(|home| home.join(".android").join("adbkey")) .ok_or(RustADBError::NoHomeDirectory) }