diff --git a/Cargo.toml b/Cargo.toml index c1b861b..15ce85d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,8 +9,9 @@ authors = ["G2 "] license = "AGPL-3.0" [dependencies] -rusb = "0.9.3" +hex = "0.4.3" translit = "0.5.0" +webusb = "0.5.0" [dependencies.minidisc-rs] path = "minidisc-rs" diff --git a/minidisc-rs/Cargo.toml b/minidisc-rs/Cargo.toml index 5ceea67..00dbde5 100644 --- a/minidisc-rs/Cargo.toml +++ b/minidisc-rs/Cargo.toml @@ -14,10 +14,15 @@ readme = "README.md" [dependencies] diacritics = "0.2.0" encoding_rs = "0.8.33" +magic-crypt = "3.1.12" nofmt = "1.0.0" once_cell = "1.18.0" regex = "1.9.5" -rusb = "0.9.3" unicode-jp = "0.4.0" unicode-normalization = "0.1.22" +hex = "0.4.3" +des = "0.8.1" +webusb = "0.5.0" +[lib] +crate-type = ["cdylib", "rlib"] diff --git a/minidisc-rs/src/netmd/base.rs b/minidisc-rs/src/netmd/base.rs index 7082f52..eb7bc59 100644 --- a/minidisc-rs/src/netmd/base.rs +++ b/minidisc-rs/src/netmd/base.rs @@ -1,14 +1,10 @@ use nofmt; use once_cell::sync::Lazy; -use rusb::{DeviceDescriptor, DeviceHandle, Direction, GlobalContext, Recipient, RequestType}; +use webusb::{UsbDevice, UsbRecipient, UsbRequestType, UsbControlTransferParameters}; use std::error::Error; const DEFAULT_TIMEOUT: std::time::Duration = std::time::Duration::new(9999999, 0); -const STANDARD_SEND: u8 = - rusb::request_type(Direction::Out, RequestType::Vendor, Recipient::Interface); -const STANDARD_RECV: u8 = - rusb::request_type(Direction::In, RequestType::Vendor, Recipient::Interface); const BULK_WRITE_ENDPOINT: u8 = 0x02; const BULK_READ_ENDPOINT: u8 = 0x81; @@ -87,7 +83,7 @@ pub struct DeviceId { } pub struct NetMD { - device_connection: DeviceHandle, + device_connection: UsbDevice, model: DeviceId, status: Option, } @@ -97,12 +93,11 @@ impl NetMD { /// Creates a new `NetMD` struct pub fn new( - device: DeviceHandle, - device_desc: DeviceDescriptor, + device: UsbDevice, ) -> Result> { let mut model = DeviceId { - vendor_id: device_desc.vendor_id(), - product_id: device_desc.product_id(), + vendor_id: device.vendor_id, + product_id: device.product_id, name: None, }; @@ -144,37 +139,36 @@ impl NetMD { /// Poll the device to get either the result /// of the previous command, or the status - fn poll(&self) -> Result<(u16, [u8; 4]), Box> { - // Create an array to store the result of the poll - let mut poll_result = [0u8; 4]; - - let _status = match self.device_connection.read_control( - STANDARD_RECV, - 0x01, - 0, - 0, - &mut poll_result, - DEFAULT_TIMEOUT, + pub fn poll(&mut self) -> Result<(u16, [u8; 4]), Box> { + let poll_result: [u8; 4] = match self.device_connection.control_transfer_in( + UsbControlTransferParameters { + request_type: UsbRequestType::Vendor, + recipient: UsbRecipient::Interface, + request: 0x01, + value: 0, + index: 0, + }, + 4 ) { - Ok(size) => size, - Err(error) => return Err(error.into()), + Ok(result) => result.try_into().unwrap(), + Err(error) => return Err(format!("USB error: {:?}", error).into()), }; let length_bytes = [poll_result[2], poll_result[3]]; Ok((u16::from_le_bytes(length_bytes), poll_result)) } - pub fn send_command(&self, command: Vec) -> Result<(), Box> { + pub fn send_command(&mut self, command: Vec) -> Result<(), Box> { self._send_command(command, false) } - pub fn send_factory_command(&self, command: Vec) -> Result<(), Box> { - self._send_command(command, false) + pub fn send_factory_command(&mut self, command: Vec) -> Result<(), Box> { + self._send_command(command, true) } /// Send a control message to the device fn _send_command( - &self, + &mut self, command: Vec, use_factory_command: bool, ) -> Result<(), Box> { @@ -192,25 +186,27 @@ impl NetMD { true => 0xff, }; - match self.device_connection.write_control( - STANDARD_SEND, - request, - 0, - 0, - &command, - DEFAULT_TIMEOUT, + match self.device_connection.control_transfer_out( + UsbControlTransferParameters { + request_type: UsbRequestType::Vendor, + recipient: UsbRecipient::Interface, + request, + value: 0, + index: 0, + }, + &command ) { Ok(_) => Ok(()), - Err(error) => Err(error.into()), + Err(error) => Err(format!("USB error: {:?}", error).into()), } } - pub fn read_reply(&self, override_length: Option) -> Result, Box> { + pub fn read_reply(&mut self, override_length: Option) -> Result, Box> { self._read_reply(false, override_length) } pub fn read_factory_reply( - &self, + &mut self, override_length: Option, ) -> Result, Box> { self._read_reply(true, override_length) @@ -219,7 +215,7 @@ impl NetMD { /// Poll to see if a message is ready, /// and if so, recieve it fn _read_reply( - &self, + &mut self, use_factory_command: bool, override_length: Option, ) -> Result, Box> { @@ -246,31 +242,31 @@ impl NetMD { }; // Create a buffer to fill with the result - let mut buf: Vec = vec![0; length as usize]; - - match self.device_connection.read_control( - STANDARD_RECV, - request, - 0, - 0, - &mut buf, - DEFAULT_TIMEOUT, + match self.device_connection.control_transfer_in( + UsbControlTransferParameters { + request_type: UsbRequestType::Vendor, + recipient: UsbRecipient::Interface, + request, + value: 0, + index: 0, + }, + length as usize ) { - Ok(_) => Ok(buf), - Err(error) => return Err(error.into()), + Ok(data) => Ok(data), + Err(error) => return Err(format!("USB error: {:?}", error).into()), } } // Default chunksize should be 0x10000 // TODO: Make these Async eventually - pub fn read_bulk(&self, length: u32, chunksize: u32) -> Result, Box> { + pub fn read_bulk(&mut self, length: u32, chunksize: u32) -> Result, Box> { let result = self.read_bulk_to_array(length, chunksize)?; - Ok(result.to_vec()) + Ok(result) } pub fn read_bulk_to_array( - &self, + &mut self, length: u32, chunksize: u32, ) -> Result, Box> { @@ -279,23 +275,31 @@ impl NetMD { while done < length { let to_read = std::cmp::min(chunksize, length - done); - let mut buffer: Vec = vec![0; to_read as usize]; + done -= to_read; + let mut buffer; - done += self.device_connection.read_bulk( + buffer = match self.device_connection.transfer_in( BULK_READ_ENDPOINT, - &mut buffer, - DEFAULT_TIMEOUT, - )? as u32; + to_read as usize, + ) { + Ok(result) => result, + Err(error) => return Err(format!("USB error: {:?}", error).into()) + }; + final_result.extend_from_slice(&mut buffer); } Ok(final_result) } - pub fn write_bulk(&self, data: &mut Vec) -> Result> { - let written = - self.device_connection - .write_bulk(BULK_WRITE_ENDPOINT, data, DEFAULT_TIMEOUT)?; + pub fn write_bulk(&mut self, data: &mut Vec) -> Result> { + let written = match self.device_connection.transfer_out( + BULK_WRITE_ENDPOINT, + data + ) { + Ok(output) => output, + Err(error) => return Err(format!("USB error: {:?}", error).into()) + }; Ok(written) } diff --git a/minidisc-rs/src/netmd/interface.rs b/minidisc-rs/src/netmd/interface.rs index 2277f46..fd1e430 100644 --- a/minidisc-rs/src/netmd/interface.rs +++ b/minidisc-rs/src/netmd/interface.rs @@ -5,9 +5,13 @@ use crate::netmd::utils::{ sanitize_full_width_title, sanitize_half_width_title, time_to_duration }; use encoding_rs::*; -use rusb; use std::collections::HashMap; use std::error::Error; +use magic_crypt::{MagicCrypt, SecureBit, MagicCryptTrait, new_magic_crypt}; +use hex; +use std::thread::sleep; +use std::time::Duration; +use webusb; #[derive(Copy, Clone)] enum Action { @@ -188,14 +192,13 @@ impl NetMDInterface { const INTERIM_RESPONSE_RETRY_INTERVAL: u32 = 100; pub fn new( - device: rusb::DeviceHandle, - descriptor: rusb::DeviceDescriptor, + device: webusb::UsbDevice, ) -> Result> { - let net_md_device = base::NetMD::new(device, descriptor).unwrap(); + let net_md_device = base::NetMD::new(device).unwrap(); Ok(NetMDInterface { net_md_device }) } - fn construct_multibyte(&self, buffer: &Vec, n: u8, offset: &mut usize) -> u32 { + fn construct_multibyte(&mut self, buffer: &Vec, n: u8, offset: &mut usize) -> u32 { let mut output: u32 = 0; for _ in 0..n as usize { output <<= 8; @@ -206,7 +209,7 @@ impl NetMDInterface { } // TODO: Finish proper implementation - fn disc_subunit_identifier(&self) -> Result> { + fn disc_subunit_identifier(&mut self) -> Result> { self.change_descriptor_state( &Descriptor::DiscSubunitIdentifier, &DescriptorAction::OpenRead, @@ -291,7 +294,7 @@ impl NetMDInterface { } /* TODO: Finish implementation - fn factory(&self) -> Result> { + fn factory(&mut self) -> Result> { let device_name = self.net_md_device.device_name().expect("The device has no name"); let himd = device_name.contains("MZ-RH") || device_name.contains("MZ-NH"); @@ -302,13 +305,13 @@ impl NetMDInterface { } */ - fn net_md_level(&self) -> Result> { + fn net_md_level(&mut self) -> Result> { let result = self.disc_subunit_identifier()?; Ok(result) } - fn change_descriptor_state(&self, descriptor: &Descriptor, action: &DescriptorAction) { + fn change_descriptor_state(&mut self, descriptor: &Descriptor, action: &DescriptorAction) { let mut query = format_query("1808".to_string(), vec![]).unwrap(); query.append(&mut descriptor.get_array()); @@ -322,7 +325,7 @@ impl NetMDInterface { /// Send a query to the NetMD player fn send_query( - &self, + &mut self, query: &mut Vec, test: bool, accept_interim: bool, @@ -334,7 +337,7 @@ impl NetMDInterface { Ok(result) } - fn send_command(&self, query: &mut Vec, test: bool) -> Result<(), Box> { + fn send_command(&mut self, query: &mut Vec, test: bool) -> Result<(), Box> { let status_byte = match test { true => Status::GeneralInquiry, false => Status::Control, @@ -350,7 +353,7 @@ impl NetMDInterface { Ok(()) } - fn read_reply(&self, accept_interim: bool) -> Result, Box> { + fn read_reply(&mut self, accept_interim: bool) -> Result, Box> { let mut current_attempt = 0; let mut data; @@ -390,7 +393,7 @@ impl NetMDInterface { Err("The max retries is set to 0".into()) } - fn playback_control(&self, action: Action) -> Result<(), Box> { + fn playback_control(&mut self, action: Action) -> Result<(), Box> { let mut query = format_query( "18c3 00 %b 000000".to_string(), vec![QueryValue::Number(action as i64)], @@ -403,24 +406,24 @@ impl NetMDInterface { Ok(()) } - pub fn play(&self) -> Result<(), Box> { + pub fn play(&mut self) -> Result<(), Box> { self.playback_control(Action::Play) } - pub fn fast_forward(&self) -> Result<(), Box> { + pub fn fast_forward(&mut self) -> Result<(), Box> { self.playback_control(Action::FastForward) } - pub fn rewind(&self) -> Result<(), Box> { + pub fn rewind(&mut self) -> Result<(), Box> { self.playback_control(Action::Rewind) } - pub fn pause(&self) -> Result<(), Box> { + pub fn pause(&mut self) -> Result<(), Box> { self.playback_control(Action::Pause) } //TODO: Implement fix for LAM-1 - pub fn stop(&self) -> Result<(), Box> { + pub fn stop(&mut self) -> Result<(), Box> { let mut query = format_query("18c5 ff 00000000".to_string(), vec![])?; let reply = self.send_query(&mut query, false, false)?; @@ -430,7 +433,7 @@ impl NetMDInterface { Ok(()) } - fn acquire(&self) -> Result<(), Box> { + fn acquire(&mut self) -> Result<(), Box> { let mut query = format_query( "ff 010c ffff ffff ffff ffff ffff ffff".to_string(), vec![], @@ -442,7 +445,7 @@ impl NetMDInterface { Ok(()) } - fn release(&self) -> Result<(), Box> { + fn release(&mut self) -> Result<(), Box> { let mut query = format_query( "ff 0100 ffff ffff ffff ffff ffff ffff".to_string(), vec![], @@ -455,7 +458,7 @@ impl NetMDInterface { Ok(()) } - pub fn status(&self) -> Result, Box> { + pub fn status(&mut self) -> Result, Box> { self.change_descriptor_state( &Descriptor::OperatingStatusBlock, &DescriptorAction::OpenRead, @@ -480,7 +483,7 @@ impl NetMDInterface { Ok(final_array) } - pub fn disc_present(&self) -> Result> { + pub fn disc_present(&mut self) -> Result> { let status = self.status()?; println!("{:X?}", status); @@ -488,7 +491,7 @@ impl NetMDInterface { Ok(status[4] == 0x40) } - fn full_operating_status(&self) -> Result<(u8, u16), Box> { + fn full_operating_status(&mut self) -> Result<(u8, u16), Box> { // WARNING: Does not work for all devices. See https://github.com/cybercase/webminidisc/issues/21 self.change_descriptor_state( &Descriptor::OperatingStatusBlock, @@ -521,13 +524,13 @@ impl NetMDInterface { Ok((status_mode, operating_status_number)) } - pub fn operating_status(&self) -> Result> { + pub fn operating_status(&mut self) -> Result> { let status = self.full_operating_status()?.1; Ok(status) } - fn playback_status_query(&self, p1: u32, p2: u32) -> Result, Box> { + fn playback_status_query(&mut self, p1: u32, p2: u32) -> Result, Box> { self.change_descriptor_state( &Descriptor::OperatingStatusBlock, &DescriptorAction::OpenRead, @@ -550,15 +553,15 @@ impl NetMDInterface { Ok(res.unwrap()[0].to_vec().unwrap()) } - pub fn playback_status1(&self) -> Result, Box> { + pub fn playback_status1(&mut self) -> Result, Box> { self.playback_status_query(0x8801, 0x8807) } - pub fn playback_status2(&self) -> Result, Box> { + pub fn playback_status2(&mut self) -> Result, Box> { self.playback_status_query(0x8802, 0x8806) } - pub fn position(&self) -> Result<[u16; 5], Box> { + pub fn position(&mut self) -> Result<[u16; 5], Box> { self.change_descriptor_state( &Descriptor::OperatingStatusBlock, &DescriptorAction::OpenRead, @@ -591,14 +594,14 @@ impl NetMDInterface { Ok(final_result) } - pub fn eject_disc(&self) -> Result<(), Box> { + pub fn eject_disc(&mut self) -> Result<(), Box> { let mut query = format_query("18c1 ff 6000".to_string(), vec![]).unwrap(); let _reply = self.send_query(&mut query, false, false)?; Ok(()) } - pub fn can_eject_disc(&self) -> Result> { + pub fn can_eject_disc(&mut self) -> Result> { let mut query = format_query("18c1 ff 6000".to_string(), vec![]).unwrap(); match self.send_query(&mut query, true, false) { @@ -608,7 +611,7 @@ impl NetMDInterface { } /* Track control */ - pub fn go_to_track(&self, track_number: u16) -> Result> { + pub fn go_to_track(&mut self, track_number: u16) -> Result> { let mut query = format_query( "1850 ff010000 0000 %w".to_string(), vec![QueryValue::Number(track_number as i64)], @@ -625,7 +628,7 @@ impl NetMDInterface { } pub fn go_to_time( - &self, + &mut self, track_number: u16, hour: u8, minute: u8, @@ -653,7 +656,7 @@ impl NetMDInterface { Ok(value as u16) } - fn _track_change(&self, direction: Track) -> Result<(), Box> { + fn _track_change(&mut self, direction: Track) -> Result<(), Box> { let mut query = format_query( "1850 ff10 00000000 %w".to_string(), vec![QueryValue::Number(direction as i64)], @@ -668,22 +671,22 @@ impl NetMDInterface { } /// Change to the next track (skip forward) - pub fn next_track(&self) -> Result<(), Box> { + pub fn next_track(&mut self) -> Result<(), Box> { self._track_change(Track::Next) } /// Change to the next track (skip back) - pub fn previous_track(&self) -> Result<(), Box> { + pub fn previous_track(&mut self) -> Result<(), Box> { self._track_change(Track::Next) } /// Change to the next track (skip to beginning of track) - pub fn restart_track(&self) -> Result<(), Box> { + pub fn restart_track(&mut self) -> Result<(), Box> { self._track_change(Track::Next) } /* Content access and control */ - pub fn erase_disc(&self) -> Result<(), Box> { + pub fn erase_disc(&mut self) -> Result<(), Box> { let mut query = format_query("1840 ff 0000".to_string(), vec![]).unwrap(); let reply = self.send_query(&mut query, false, false)?; scan_query(reply, "1840 00 0000".to_string())?; @@ -692,7 +695,7 @@ impl NetMDInterface { // TODO: Ensure this is returning the correct value, it // looks like it actually might be a 16 bit integer - pub fn disc_flags(&self) -> Result> { + pub fn disc_flags(&mut self) -> Result> { self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead); let mut query = format_query("1806 01101000 ff00 0001000b".to_string(), vec![]).unwrap(); @@ -707,7 +710,7 @@ impl NetMDInterface { } /// The number of tracks on the disc - pub fn track_count(&self) -> Result> { + pub fn track_count(&mut self) -> Result> { self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead); let mut query = format_query( @@ -729,7 +732,7 @@ impl NetMDInterface { Ok(res[0].to_i64().unwrap() as u16) } - fn _disc_title(&self, wchar: bool) -> Result> { + fn _disc_title(&mut self, wchar: bool) -> Result> { self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead); self.change_descriptor_state(&Descriptor::DiscTitleTD, &DescriptorAction::OpenRead); @@ -792,7 +795,7 @@ impl NetMDInterface { } /// Gets the disc title - pub fn disc_title(&self, wchar: bool) -> Result> { + pub fn disc_title(&mut self, wchar: bool) -> Result> { let mut title = self._disc_title(wchar)?; let delim = match wchar { @@ -818,9 +821,7 @@ impl NetMDInterface { } /// Gets all groups on the disc - pub fn track_group_list( - &self, - ) -> Result, Option, Vec)>, Box> { + pub fn track_group_list(&mut self) -> Result, Option, Vec)>, Box> { let raw_title = self._disc_title(false)?; let group_list = raw_title.split("//"); let mut track_dict: HashMap = HashMap::new(); @@ -904,7 +905,7 @@ impl NetMDInterface { } /// Gets a list of track titles from a set - pub fn track_titles(&self, tracks: Vec, wchar: bool) -> Result, Box> { + pub fn track_titles(&mut self, tracks: Vec, wchar: bool) -> Result, Box> { let wchar_value = match wchar { true => 3, false => 2, @@ -945,13 +946,17 @@ impl NetMDInterface { } /// Gets the title of a track at an index - pub fn track_title(&self, track: u16, wchar: bool) -> Result> { - let title = self.track_titles([track].into(), wchar).unwrap()[0].clone(); + pub fn track_title(&mut self, track: u16, wchar: bool) -> Result> { + let title = match self.track_titles([track].into(), wchar) { + Ok(titles) => titles[0].clone(), + Err(error) if error.to_string() == "Rejected" => String::new(), + Err(error) => return Err(error) + }; Ok(title) } // Sets the title of the disc - pub fn set_disc_title(&self, title: String, wchar: bool) -> Result<(), Box> { + pub fn set_disc_title(&mut self, title: String, wchar: bool) -> Result<(), Box> { let current_title = self._disc_title(wchar)?; if current_title == title { return Ok(()); @@ -1004,7 +1009,7 @@ impl NetMDInterface { } /// Sets the title of a track - pub fn set_track_title(&self, track: u16, title: String, wchar: bool) -> Result<(), Box> { + pub fn set_track_title(&mut self, track: u16, title: String, wchar: bool) -> Result<(), Box> { let new_title: Vec; let (wchar_value, descriptor) = match wchar { true => { @@ -1055,7 +1060,7 @@ impl NetMDInterface { } /// Removes a track from the UTOC - pub fn erase_track(&self, track: u16) -> Result<(), Box> { + pub fn erase_track(&mut self, track: u16) -> Result<(), Box> { let mut query = format_query( "1840 ff01 00 201001 %w".to_string(), vec![ @@ -1069,7 +1074,7 @@ impl NetMDInterface { } /// Moves a track to another position on the disc - pub fn move_track(&self, source: u16, dest: u16) -> Result<(), Box> { + pub fn move_track(&mut self, source: u16, dest: u16) -> Result<(), Box> { let mut query = format_query( "1843 ff00 00 201001 %w 201001 %w".to_string(), vec![ @@ -1083,7 +1088,7 @@ impl NetMDInterface { Ok(()) } - fn _track_info(&self, track: u16, p1: i32, p2: i32) -> Result, Box> { + fn _track_info(&mut self, track: u16, p1: i32, p2: i32) -> Result, Box> { self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead); let mut query = format_query( @@ -1104,7 +1109,7 @@ impl NetMDInterface { } /// Gets the length of tracks as a `std::time::Duration` from a set - pub fn track_lengths(&self, tracks: Vec) -> Result, Box> { + pub fn track_lengths(&mut self, tracks: Vec) -> Result, Box> { let mut times: Vec = vec![]; self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead); @@ -1136,12 +1141,12 @@ impl NetMDInterface { } /// Gets the length of a track as a `std::time::Duration` - pub fn track_length(&self, track: u16) -> Result> { + pub fn track_length(&mut self, track: u16) -> Result> { Ok(self.track_lengths([track].into())?[0]) } /// Gets the encoding of a track (SP, LP2, LP4) - pub fn track_encoding(&self, track_number: u16) -> Result> { + pub fn track_encoding(&mut self, track_number: u16) -> Result> { let raw_value = self._track_info(track_number, 0x3080, 0x0700)?; let result = scan_query(raw_value, "07 0004 0110 %b %b".to_string())?; @@ -1157,7 +1162,7 @@ impl NetMDInterface { } /// Gets a track's flags - pub fn track_flags(&self, track: u16) -> Result> { + pub fn track_flags(&mut self, track: u16) -> Result> { self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead); let mut query = format_query( "1806 01201001 %w ff00 00010008".to_string(), @@ -1175,7 +1180,7 @@ impl NetMDInterface { } /// Gets the disc capacity as a `std::time::Duration` - pub fn disc_capacity(&self) -> Result<[std::time::Duration; 3], Box> { + pub fn disc_capacity(&mut self) -> Result<[std::time::Duration; 3], Box> { self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead); let mut query = format_query( "1806 02101000 3080 0300 ff00 00000000".to_string(), @@ -1203,7 +1208,7 @@ impl NetMDInterface { Ok(result) } - pub fn recording_parameters(&self) -> Result, Box> { + pub fn recording_parameters(&mut self) -> Result, Box> { self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::OpenRead); let mut query = format_query( "1809 8001 0330 8801 0030 8805 0030 8807 00 ff00 00000000".to_string(), @@ -1222,7 +1227,7 @@ impl NetMDInterface { /// Gets the bytes of a track /// /// This can only be executed on an MZ-RH1 / M200 - pub fn save_track_to_array(&self, track: u16) -> Result<(DiscFormat, u16, Vec), Box> { + pub fn save_track_to_array(&mut self, track: u16) -> Result<(DiscFormat, u16, Vec), Box> { let mut query = format_query( "1800 080046 f003010330 ff00 1001 %w".to_string(), vec![ @@ -1254,4 +1259,332 @@ impl NetMDInterface { Ok((format, frames, result)) } + + pub fn disable_new_track_protection(&mut self, val: u16) -> Result<(), Box> { + let mut query = format_query( + "1800 080046 f0030103 2b ff %w".to_string(), + vec![ + QueryValue::Number(val as i64) + ], + )?; + + let reply = self.send_query(&mut query, false, false)?; + scan_query(reply, "1800 080046 f0030103 2b 00 %?%?".to_string())?; + Ok(()) + } + + pub fn enter_secure_session(&mut self) -> Result<(), Box> { + let mut query = format_query( + "1800 080046 f0030103 80 ff".to_string(), + vec![], + )?; + + let reply = self.send_query(&mut query, false, false)?; + scan_query(reply, "1800 080046 f0030103 80 00".to_string())?; + Ok(()) + } + + pub fn leave_secure_session(&mut self) -> Result<(), Box> { + let mut query = format_query( + "1800 080046 f0030103 81 ff".to_string(), + vec![], + )?; + + let reply = self.send_query(&mut query, false, false)?; + scan_query(reply, "1800 080046 f0030103 81 00".to_string())?; + Ok(()) + } + + /** + Read the leaf ID of the present NetMD device. The leaf ID tells + which keys the device posesses, which is needed to find out which + parts of the EKB needs to be sent to the device for it to decrypt + the root key. + The leaf ID is a 8-byte constant + **/ + pub fn leaf_id(&mut self) -> Result, Box> { + let mut query = format_query( + "1800 080046 f0030103 11 ff".to_string(), + vec![], + )?; + + let reply = self.send_query(&mut query, false, false)?; + let res = scan_query(reply, "1800 080046 f0030103 11 00 %*".to_string())?; + + Ok(res[0].to_vec().unwrap()) + } + + pub fn send_key_data(&mut self, ekbid: i32, keychain: Vec<[u8; 16]>, depth: i32, ekbsignature: Vec) -> Result, Box> { + let chainlen = keychain.len(); + let databytes = 16 + 16 * chainlen + 24; + + if depth < 1 || depth > 63 { + return Err("Supplied depth is invalid".into()); + } + if ekbsignature.len() != 24 { + return Err("Supplied EKB signature length wrong".into()); + } + + let keychains = keychain.concat(); + + let mut query = format_query( + "1800 080046 f0030103 12 ff %w 0000 %w %d %d %d 00000000 %* %*".to_string(), + vec![ + QueryValue::Number(databytes as i64), + QueryValue::Number(databytes as i64), + QueryValue::Number(chainlen as i64), + QueryValue::Number(depth as i64), + QueryValue::Number(ekbid as i64), + QueryValue::Array(keychains), + QueryValue::Array(ekbsignature), + ], + )?; + + let reply = self.send_query(&mut query, false, false)?; + + let res = scan_query(reply, "1800 080046 f0030103 12 01 %?%? %?%?%?%?".to_string())?; + + Ok(res[0].to_vec().unwrap()) + } + + pub fn session_key_exchange(&mut self, hostnonce: Vec) -> Result, Box> { + if hostnonce.len() != 8 { + return Err("Supplied host nonce length wrong".into()); + } + let mut query = format_query( + "1800 080046 f0030103 20 ff 000000 %*".to_string(), + vec![QueryValue::Array(hostnonce)], + )?; + + let reply = self.send_query(&mut query, false, false)?; + + let res = scan_query(reply, "1800 080046 f0030103 20 %? 000000 %#".to_string())?; + + Ok(res[0].to_vec().unwrap()) + } + + pub fn session_key_forget(&mut self) -> Result<(), Box> { + let mut query = format_query( + "1800 080046 f0030103 21 ff 000000".to_string(), + vec![], + )?; + + let reply = self.send_query(&mut query, false, false)?; + let _ = scan_query(reply, "1800 080046 f0030103 21 00 000000".to_string())?; + + Ok(()) + } + + pub fn setup_download(&mut self, contentid: Vec, keyenckey: Vec, hex_session_key: String) -> Result<(), Box> { + if contentid.len() != 20 { + return Err("Supplied content ID length wrong".into()); + } + if keyenckey.len() != 8 { + return Err("Supplied Key Encryption Key length wrong".into()); + } + if hex_session_key.len() != 16 { + return Err("Supplied Session Key length wrong".into()); + } + + let message = vec![vec![1, 1, 1, 1], contentid, keyenckey].concat(); + + let mc = MagicCrypt::new( + hex_session_key, + SecureBit::Bit256, + None:: + ); + + let encryptedarg = mc.decrypt_bytes_to_bytes(&message)?; + + let mut query = format_query( + "1800 080046 f0030103 22 ff 0000 %*".to_string(), + vec![ + QueryValue::Array(encryptedarg) + ], + )?; + + let reply = self.send_query(&mut query, false, false)?; + + scan_query(reply, "1800 080046 f0030103 22 00 0000".to_string())?; + + Ok(()) + } + + pub fn commit_track(&mut self, track_number: u16, hex_session_key: String) -> Result<(), Box> { + if hex_session_key.len() != 16 { + return Err("Supplied Session Key length wrong".into()); + } + + let mc = new_magic_crypt!(hex::encode(hex_session_key), 256); + let authentication = mc.encrypt_str_to_bytes(hex::encode("0000000000000000")); + + let mut query = format_query( + "1800 080046 f0030103 22 ff 0000 %*".to_string(), + vec![ + QueryValue::Number(track_number as i64), + QueryValue::Array(authentication) + ], + )?; + + let reply = self.send_query(&mut query, false, false)?; + + scan_query(reply, "1800 080046 f0030103 22 00 0000".to_string())?; + + Ok(()) + } + + pub fn send_track(&mut self, + wireformat: u8, + discformat: u8, + frames: i32, + pkt_size: u32, + // key // iv // data + packets: Vec<(Vec, Vec, Vec)>, + hex_session_key: String + ) -> Result<(i64, String, String), Box> { + if hex_session_key.len() != 16 { + return Err("Supplied Session Key length wrong".into()); + } + + // Sharps are slow + sleep(Duration::from_millis(200)); + + let total_bytes = pkt_size + 24; //framesizedict[wireformat] * frames + pktcount * 24; + + let mut query = format_query("1800 080046 f0030103 28 ff 000100 1001 ffff 00 %b %b %d %d".to_string(), + vec![ + QueryValue::Number(wireformat as i64), + QueryValue::Number(discformat as i64), + QueryValue::Number(frames as i64), + QueryValue::Number(total_bytes as i64), + ] + )?; + let mut reply = self.send_query(&mut query, false, true)?; + scan_query(reply, "1800 080046 f0030103 28 00 000100 1001 %?%? 00 %*".to_string())?; + + // Sharps are slow + sleep(Duration::from_millis(200)); + + let mut packet_count = 0; + let mut written_bytes = 0; + for (key, iv, data) in packets { + let mut binpack; + if packet_count == 0 { + let packed_length: Vec = pkt_size.to_le_bytes().to_vec(); + binpack = vec![vec![0, 0, 0, 0], packed_length, key, iv, data.clone()].concat(); + } else { + binpack = data.clone(); + } + self.net_md_device.write_bulk(&mut binpack)?; + packet_count += 1; + written_bytes += data.len(); + } + + reply = self.read_reply(false)?; + self.net_md_device.poll()?; + let res = scan_query(reply, "1800 080046 f0030103 28 00 000100 1001 %w 00 %?%? %?%?%?%? %?%?%?%? %*".to_string())?; + + let mc = MagicCrypt::new( + hex_session_key, + SecureBit::Bit256, + Some("0000000000000000") + ); + + let reply_data = String::from_utf8(mc.decrypt_bytes_to_bytes(&res[1].to_vec().unwrap())?).unwrap().chars().collect::>(); + + let part1 = String::from_iter(reply_data.clone()[0..8].into_iter()); + let part2 = String::from_iter(reply_data.clone()[12..32].into_iter()); + + Ok((res[0].to_i64().unwrap(), part1, part2)) + } + + pub fn track_uuid(&mut self, track: u16) -> Result> { + let mut query = format_query( + "1800 080046 f0030103 23 ff 1001 %w".to_string(), + vec![ + QueryValue::Number(track as i64), + ], + )?; + let reply = self.send_query(&mut query, false, false)?; + + let res = scan_query(reply, "1800 080046 f0030103 23 00 1001 %?%? %*".to_string())?; + + Ok(String::from_utf8_lossy(&res[0].to_vec().unwrap()).to_string()) + } + + pub fn terminate(&mut self) -> Result<(), Box> { + let mut query = format_query( + "1800 080046 f0030103 2a ff00".to_string(), + vec![], + )?; + self.send_query(&mut query, false, false)?; + + Ok(()) + } +} + +pub fn retailmac( + key: Vec, + value: Vec, + iv: Vec +) -> Result<(), Box> { + let subkey_a = key[0..8].to_vec(); + let beginning = value[0..value.len() - 8].to_vec(); + let end = value[value.len() - 8..].to_vec(); + + let mc = MagicCrypt::new( + String::from_utf8(subkey_a).unwrap(), + SecureBit::Bit256, + Some(String::from_utf8(iv).unwrap()) + ); + let step1 = mc.encrypt_bytes_to_bytes(&beginning); + + let iv2 = String::from_utf8(step1); + + Ok(()) +} + +struct EKBOpenSource { + +} + +impl EKBOpenSource { + fn root_key(&mut self) -> [u8; 16] { + [ + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, + 0x0f, 0xed, 0xcb, 0xa9, 0x87, 0x65, 0x43, 0x21 + ] + } + + fn ekb_id(&mut self) -> i32 { + 0x26422642 + } + + /* What's this for? + ekb_data_for_leaf_id(): [Uint8Array[], number, Uint8Array] { + return [ + [ + new Uint8Array([0x25, 0x45, 0x06, 0x4d, 0xea, 0xca, 0x14, 0xf9, 0x96, 0xbd, 0xc8, 0xa4, 0x06, 0xc2, 0x2b, 0x81]), + new Uint8Array([0xfb, 0x60, 0xbd, 0xdd, 0x0d, 0xbc, 0xab, 0x84, 0x8a, 0x00, 0x5e, 0x03, 0x19, 0x4d, 0x3e, 0xda]), + ], + 9, + new Uint8Array([ + 0x8f, 0x2b, 0xc3, 0x52, 0xe8, 0x6c, 0x5e, 0xd3, 0x06, 0xdc, 0xae, 0x18, + 0xd2, 0xf3, 0x8c, 0x7f, 0x89, 0xb5, 0xe1, 0x85, 0x55, 0xa1, 0x05, 0xea + ]) + ]; + } + */ +} + +struct MDTrack { + title: String, + format: WireFormat, + data: Vec, + chunk_size: i32, + full_width_title: Option, +} + +impl MDTrack { + } diff --git a/src/main.rs b/src/main.rs index 8d92e1c..300690a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,94 +2,50 @@ use std::thread::sleep; use std::collections::BTreeSet; use minidisc_rs::netmd::interface; -use rusb; +use webusb; fn main() { - let mut die = false; - for device in rusb::devices().unwrap().iter() { - if die { - break; - } - - let device_desc = device.device_descriptor().unwrap(); + let webusb_context = webusb::Context::init().unwrap(); - let new_device = match device.open() { + for mut device in webusb_context.devices().unwrap() { + match device.open() { Ok(device) => device, - Err(_) => continue, + Err(_) => break, }; - die = true; + + device.claim_interface(0).unwrap(); println!( - "Connected to Bus {:03} Device {:03} VID: {:04x}, PID: {:04x}, {:?}", - device.bus_number(), - device.address(), - device_desc.vendor_id(), - device_desc.product_id(), - new_device.read_product_string_ascii(&device_desc) + "Connected to {} {}; VID: {:04x}, PID: {:04x}", + device.manufacturer_name.clone().unwrap_or("".to_string()), + device.product_name.clone().unwrap_or("".to_string()), + device.vendor_id, + device.product_id ); // Ensure the player is a minidisc player and not some other random device - let player_controller = match interface::NetMDInterface::new(new_device, device_desc) { + let mut player_controller = match interface::NetMDInterface::new(device) { Ok(player) => player, Err(_) => continue }; - println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); - println!( - "Player Model: {}", - player_controller.net_md_device.device_name().clone().unwrap() + println!("Player Model: {}", player_controller.net_md_device.device_name().clone().unwrap()); + + let now = std::time::Instant::now(); + println!("Disc Title: {} | {}", + player_controller.disc_title(false).unwrap_or("".to_string()), + player_controller.disc_title(true).unwrap_or("".to_string()) ); - //println!("TEST CASE: {:?}", player_controller.set_track_title(3, "初音ミクの消失".to_string(), false).unwrap()); - - let track_count = player_controller.track_count().unwrap(); - - let now = std::time::SystemTime::now(); - let times = player_controller.track_lengths((0u16..track_count).collect()).unwrap(); - let titles_hw = player_controller.track_titles((0u16..track_count).collect(), false).unwrap(); - let titles_fw = player_controller.track_titles((0u16..track_count).collect(), true).unwrap(); - - /* - let now = std::time::SystemTime::now(); - for i in 0..player_controller.track_count().unwrap() { - player_controller.track_length(i as u16); - player_controller.track_title(i as u16, false); - player_controller.track_title(i as u16, true); - } - println!("Individual: {}ms", now.elapsed().unwrap().as_millis()); - */ - - println!( - " -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -Tracks: {:0>2}, Length: {:0>2} minutes -───────────────┬┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┬┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ - │ Half Width │ Full Width -━━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━ - Disc Title: │ {: >21} │ {} -────┬──────────┼───────────────────────┼─────────────────────────", - track_count, - player_controller.disc_capacity().unwrap()[0].as_secs() / 60, - player_controller.disc_title(false).unwrap(), - player_controller.disc_title(true).unwrap() - ); - - for i in 0..track_count { - println!( - " {: >2} │ {:0>2}:{:0>2}:{:0>2} │ {: >21} │ {}", - i + 1, - (times[i as usize].as_secs() / 60) / 60, - (times[i as usize].as_secs() / 60) % 60, - times[i as usize].as_secs() % 60, - titles_hw[i as usize], - titles_fw[i as usize] + let track_count = player_controller.track_count().unwrap(); + let track_titles = player_controller.track_titles((0..track_count).collect(), false).unwrap(); + let track_titlesw = player_controller.track_titles((0..track_count).collect(), true).unwrap(); + let track_lengths = player_controller.track_lengths((0..track_count).collect()).unwrap(); + for (i, track) in track_titles.iter().enumerate() { + println!("Track {i} Info:\n Title: {track} | {}\n Length: {:?}", + track_titlesw[i], + track_lengths[i] ); } - println!("────┴──────────┴───────────────────────┴─────────────────────────\nFinished in: [{}ms]", now.elapsed().unwrap().as_millis()); - - - println!("\n\n\nAttempting to get track 1"); - let returned_bytes = player_controller.save_track_to_array(0); - - println!("\n{:?}", returned_bytes); + println!("{:?}", now.elapsed()); } }