diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4752ca14..b760e269 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,3 +36,8 @@ jobs: # Probably has to do with forking the test processes. run: meson test --interactive working-directory: build/ + - name: Check clippy recommendations + run: env CARGO_HOME=build/cargo-home cargo clippy --manifest-path xyz-iinuwa-credential-manager-portal-gtk/Cargo.toml --target-dir build/xyz-iinuwa-credential-manager-portal-gtk/src + - name: Check formatting + run: cargo fmt --check + working-directory: xyz-iinuwa-credential-manager-portal-gtk diff --git a/xyz-iinuwa-credential-manager-portal-gtk/src/application.rs b/xyz-iinuwa-credential-manager-portal-gtk/src/application.rs index 115f38f8..84dd3030 100644 --- a/xyz-iinuwa-credential-manager-portal-gtk/src/application.rs +++ b/xyz-iinuwa-credential-manager-portal-gtk/src/application.rs @@ -57,11 +57,13 @@ mod imp { vm2.clone().connect_completed_notify(move |vm| { if vm.completed() { glib::spawn_future_local(clone!( - #[weak] window2, + #[weak] + window2, async move { // Wait to show confirmation before closing. async_std::task::sleep(Duration::from_millis(500)).await; - gtk::prelude::WidgetExt::activate_action(&window2, "window.close", None).unwrap() + gtk::prelude::WidgetExt::activate_action(&window2, "window.close", None) + .unwrap() } )); } diff --git a/xyz-iinuwa-credential-manager-portal-gtk/src/cbor.rs b/xyz-iinuwa-credential-manager-portal-gtk/src/cbor.rs index 7883d6d7..9a3c5f11 100644 --- a/xyz-iinuwa-credential-manager-portal-gtk/src/cbor.rs +++ b/xyz-iinuwa-credential-manager-portal-gtk/src/cbor.rs @@ -75,7 +75,6 @@ where Ok(()) } - pub fn write_text(&mut self, text: &str) -> Result<(), Error> { let data = text.as_bytes(); self.write_cbor_value( diff --git a/xyz-iinuwa-credential-manager-portal-gtk/src/cose.rs b/xyz-iinuwa-credential-manager-portal-gtk/src/cose.rs index 10e9a22d..752336f5 100644 --- a/xyz-iinuwa-credential-manager-portal-gtk/src/cose.rs +++ b/xyz-iinuwa-credential-manager-portal-gtk/src/cose.rs @@ -1,10 +1,9 @@ - use libwebauthn::proto::ctap2::Ctap2COSEAlgorithmIdentifier; use ring::{ - rand::SystemRandom, signature::{ - EcdsaKeyPair, Ed25519KeyPair, KeyPair, - RsaKeyPair, ECDSA_P256_SHA256_ASN1_SIGNING, - } + rand::SystemRandom, + signature::{ + EcdsaKeyPair, Ed25519KeyPair, KeyPair, RsaKeyPair, ECDSA_P256_SHA256_ASN1_SIGNING, + }, }; use tracing::debug; @@ -48,9 +47,18 @@ impl CoseKeyParameters { impl From for CoseKeyParameters { fn from(value: CoseKeyType) -> Self { match value { - CoseKeyType::ES256_P256 => CoseKeyParameters { alg: CoseKeyAlgorithmIdentifier::ES256, crv: Some(CoseEllipticCurveIdentifier::P256) }, - CoseKeyType::EDDSA_ED25519 => CoseKeyParameters { alg: CoseKeyAlgorithmIdentifier::EdDSA, crv: Some(CoseEllipticCurveIdentifier::Ed25519) }, - CoseKeyType::RS256 => CoseKeyParameters { alg: CoseKeyAlgorithmIdentifier::RS256, crv: None, }, + CoseKeyType::ES256_P256 => CoseKeyParameters { + alg: CoseKeyAlgorithmIdentifier::ES256, + crv: Some(CoseEllipticCurveIdentifier::P256), + }, + CoseKeyType::EDDSA_ED25519 => CoseKeyParameters { + alg: CoseKeyAlgorithmIdentifier::EdDSA, + crv: Some(CoseEllipticCurveIdentifier::Ed25519), + }, + CoseKeyType::RS256 => CoseKeyParameters { + alg: CoseKeyAlgorithmIdentifier::RS256, + crv: None, + }, } } } @@ -126,10 +134,7 @@ pub enum Error { Unsupported, } -pub(super) fn encode_pkcs8_key( - key_type: CoseKeyType, - pkcs8_key: &[u8], -) -> Result, Error> { +pub(super) fn encode_pkcs8_key(key_type: CoseKeyType, pkcs8_key: &[u8]) -> Result, Error> { match key_type { CoseKeyType::ES256_P256 => { let key_pair = EcdsaKeyPair::from_pkcs8( @@ -194,7 +199,7 @@ pub(super) fn encode_pkcs8_key( /// returns CTAP2-serialized public key and algorithm pub(crate) fn encode_cose_key(public_key: &cosey::PublicKey) -> Result, Error> { match public_key { - cosey::PublicKey::P256Key(p256_key) => { + cosey::PublicKey::P256Key(p256_key) => { let mut cose_key: Vec = Vec::new(); cose_key.push(0b101_00101); // map with 5 items cose_key.extend([0b000_00001, 0b000_00010]); // kty (1): EC2 (2) @@ -205,7 +210,7 @@ pub(crate) fn encode_cose_key(public_key: &cosey::PublicKey) -> Result, cose_key.extend([0b001_00010, 0b010_11000, 0b0010_0000]); // y (-3): <32-byte string> cose_key.extend(p256_key.y.clone()); Ok(cose_key) - }, + } cosey::PublicKey::Ed25519Key(ed25519_key) => { // TODO: Check this let mut cose_key: Vec = Vec::new(); @@ -216,7 +221,7 @@ pub(crate) fn encode_cose_key(public_key: &cosey::PublicKey) -> Result, cose_key.extend([0b001_00001, 0b010_11000, 0b0010_0000]); // x (-2): <32-byte string> cose_key.extend(ed25519_key.x.clone()); Ok(cose_key) - }, + } _ => { debug!("Cannot serialize unknown key type {:?}", public_key); diff --git a/xyz-iinuwa-credential-manager-portal-gtk/src/credential_service/mod.rs b/xyz-iinuwa-credential-manager-portal-gtk/src/credential_service/mod.rs index 0106e0c9..9799c591 100644 --- a/xyz-iinuwa-credential-manager-portal-gtk/src/credential_service/mod.rs +++ b/xyz-iinuwa-credential-manager-portal-gtk/src/credential_service/mod.rs @@ -402,7 +402,6 @@ impl CredentialService { } } - #[derive(Copy, Clone, Debug, Default, PartialEq)] pub enum UsbState { /// Not polling for FIDO USB device. diff --git a/xyz-iinuwa-credential-manager-portal-gtk/src/serde/mod.rs b/xyz-iinuwa-credential-manager-portal-gtk/src/serde/mod.rs index a764146e..fd0ccb08 100644 --- a/xyz-iinuwa-credential-manager-portal-gtk/src/serde/mod.rs +++ b/xyz-iinuwa-credential-manager-portal-gtk/src/serde/mod.rs @@ -4,13 +4,17 @@ pub(crate) mod b64 { use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; pub(crate) fn serialize(value: &Vec, serializer: S) -> Result - where S: Serializer { + where + S: Serializer, + { let s = URL_SAFE_NO_PAD.encode(value); String::serialize(&s, serializer) } pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where D: Deserializer<'de> { + where + D: Deserializer<'de>, + { let s = String::deserialize(deserializer)?; URL_SAFE_NO_PAD.decode(s).map_err(de::Error::custom) } @@ -22,7 +26,10 @@ pub(crate) mod duration { use serde::{Deserialize, Deserializer}; pub(crate) fn from_opt_ms<'de, D>(deserializer: D) -> Result, D::Error> - where D: Deserializer<'de> { - Option::::deserialize(deserializer).map(|ms_opt| ms_opt.map(|ms| Duration::from_millis(ms as u64))) + where + D: Deserializer<'de>, + { + Option::::deserialize(deserializer) + .map(|ms_opt| ms_opt.map(|ms| Duration::from_millis(ms as u64))) } -} \ No newline at end of file +} diff --git a/xyz-iinuwa-credential-manager-portal-gtk/src/view_model/gtk/mod.rs b/xyz-iinuwa-credential-manager-portal-gtk/src/view_model/gtk/mod.rs index a9f20be3..51c67d2f 100644 --- a/xyz-iinuwa-credential-manager-portal-gtk/src/view_model/gtk/mod.rs +++ b/xyz-iinuwa-credential-manager-portal-gtk/src/view_model/gtk/mod.rs @@ -89,7 +89,8 @@ impl ViewModel { self.imp().tx.replace(Some(tx)); self.imp().rx.replace(Some(rx)); glib::spawn_future_local(clone!( - #[weak(rename_to = view_model)] self, + #[weak(rename_to = view_model)] + self, async move { loop { let rx = view_model.imp().rx.borrow(); @@ -99,20 +100,32 @@ impl ViewModel { // TODO: hack so I don't have to unset this in every event manually. view_model.set_usb_pin_entry_visible(false); match update { - ViewUpdate::SetTitle(title) => { view_model.set_title(title) }, - ViewUpdate::SetDevices(devices) => { view_model.update_devices(&devices) }, - ViewUpdate::SetCredentials(credentials) => { view_model.update_credentials(&credentials) }, - ViewUpdate::SelectDevice(device) => { view_model.select_device(&device) }, - ViewUpdate::SelectCredential(cred_id) => { view_model.select_credential(cred_id) }, + ViewUpdate::SetTitle(title) => view_model.set_title(title), + ViewUpdate::SetDevices(devices) => { + view_model.update_devices(&devices) + } + ViewUpdate::SetCredentials(credentials) => { + view_model.update_credentials(&credentials) + } + ViewUpdate::SelectDevice(device) => { + view_model.select_device(&device) + } + ViewUpdate::SelectCredential(cred_id) => { + view_model.select_credential(cred_id) + } ViewUpdate::UsbNeedsPin { attempts_left } => { let prompt = match attempts_left { - Some(1) => "Enter your PIN. 1 attempt remaining.".to_string(), - Some(attempts_left) => format!("Enter your PIN. {attempts_left} attempts remaining."), + Some(1) => { + "Enter your PIN. 1 attempt remaining.".to_string() + } + Some(attempts_left) => format!( + "Enter your PIN. {attempts_left} attempts remaining." + ), None => format!("Enter your PIN."), }; view_model.set_prompt(prompt); view_model.set_usb_pin_entry_visible(true); - }, + } ViewUpdate::UsbNeedsUserVerification { attempts_left } => { let prompt = match attempts_left { Some(1) => "Touch your device again. 1 attempt remaining.".to_string(), @@ -120,15 +133,15 @@ impl ViewModel { None => format!("Touch your device."), }; view_model.set_prompt(prompt); - }, + } ViewUpdate::UsbNeedsUserPresence => { view_model.set_prompt("Touch your device"); - }, + } ViewUpdate::Completed => { view_model.set_completed(true); - }, + } } - }, + } Err(e) => { debug!("ViewModel event listener interrupted: {}", e); break; diff --git a/xyz-iinuwa-credential-manager-portal-gtk/src/view_model/mod.rs b/xyz-iinuwa-credential-manager-portal-gtk/src/view_model/mod.rs index 62b1951e..271c08b8 100644 --- a/xyz-iinuwa-credential-manager-portal-gtk/src/view_model/mod.rs +++ b/xyz-iinuwa-credential-manager-portal-gtk/src/view_model/mod.rs @@ -232,13 +232,16 @@ impl ViewModel { match prev_state { UsbState::Completed => break, UsbState::UserCancelled => break, - _ => {}, + _ => {} }; async_std::task::sleep(Duration::from_millis(50)).await; - }, + } Err(err) => { // TODO: move to error page - tracing::error!("There was an error trying to get credentials from USB: {}", err); + tracing::error!( + "There was an error trying to get credentials from USB: {}", + err + ); break; } }; @@ -266,9 +269,11 @@ impl ViewModel { { if prev_state != current_state { println!("{:?}", current_state); - tx.send(BackgroundEvent::InternalDeviceStateChanged(current_state.clone())) - .await - .unwrap(); + tx.send(BackgroundEvent::InternalDeviceStateChanged( + current_state.clone(), + )) + .await + .unwrap(); } prev_state = current_state; } @@ -356,19 +361,25 @@ impl ViewModel { } UsbState::NeedsPin { attempts_left } => { - self.tx_update.send(ViewUpdate::UsbNeedsPin { attempts_left }).await.unwrap(); + self.tx_update + .send(ViewUpdate::UsbNeedsPin { attempts_left }) + .await + .unwrap(); } UsbState::NeedsUserVerification { attempts_left } => { - self.tx_update.send(ViewUpdate::UsbNeedsUserVerification { attempts_left }).await.unwrap(); + self.tx_update + .send(ViewUpdate::UsbNeedsUserVerification { attempts_left }) + .await + .unwrap(); } - UsbState::NeedsUserPresence => { - self.tx_update.send(ViewUpdate::UsbNeedsUserPresence).await.unwrap(); + UsbState::NeedsUserPresence => { + self.tx_update + .send(ViewUpdate::UsbNeedsUserPresence) + .await + .unwrap(); } UsbState::Completed => { - self.credential_service - .lock() - .await - .complete_auth(); + self.credential_service.lock().await.complete_auth(); self.tx_update.send(ViewUpdate::Completed).await.unwrap(); } _ => {} @@ -381,10 +392,7 @@ impl ViewModel { // self.tx_update.send(ViewUpdate::InternalDeviceNeedsPin).await.unwrap(); // }, InternalDeviceState::Completed { device, cred_id } => { - self.credential_service - .lock() - .await - .complete_auth(); + self.credential_service.lock().await.complete_auth(); self.tx_update.send(ViewUpdate::Completed).await.unwrap(); } _ => {} @@ -547,7 +555,6 @@ impl From for String { } } - impl Transport { fn as_str(&self) -> &'static str { match self { @@ -571,10 +578,14 @@ pub enum UsbState { Waiting, /// The device needs the PIN to be entered. - NeedsPin { attempts_left: Option }, + NeedsPin { + attempts_left: Option, + }, /// The device needs on-device user verification to be entered. - NeedsUserVerification { attempts_left: Option }, + NeedsUserVerification { + attempts_left: Option, + }, /// The device needs on-device user verification to be entered. NeedsUserPresence, @@ -595,8 +606,12 @@ impl From for UsbState { crate::credential_service::UsbState::Idle => UsbState::NotListening, crate::credential_service::UsbState::Waiting => UsbState::Waiting, crate::credential_service::UsbState::Connected => UsbState::Connected, - crate::credential_service::UsbState::NeedsPin { attempts_left }=> UsbState::NeedsPin { attempts_left }, - crate::credential_service::UsbState::NeedsUserVerification { attempts_left }=> UsbState::NeedsUserVerification { attempts_left }, + crate::credential_service::UsbState::NeedsPin { attempts_left } => { + UsbState::NeedsPin { attempts_left } + } + crate::credential_service::UsbState::NeedsUserVerification { attempts_left } => { + UsbState::NeedsUserVerification { attempts_left } + } crate::credential_service::UsbState::NeedsUserPresence => UsbState::NeedsUserPresence, crate::credential_service::UsbState::Completed => UsbState::Completed, crate::credential_service::UsbState::UserCancelled => UsbState::UserCancelled, diff --git a/xyz-iinuwa-credential-manager-portal-gtk/src/window.rs b/xyz-iinuwa-credential-manager-portal-gtk/src/window.rs index 4758f1e4..00d58400 100644 --- a/xyz-iinuwa-credential-manager-portal-gtk/src/window.rs +++ b/xyz-iinuwa-credential-manager-portal-gtk/src/window.rs @@ -41,7 +41,8 @@ mod imp { let view_model = &self.view_model.borrow(); let view_model = view_model.as_ref().unwrap(); glib::spawn_future_local(clone!( - #[weak] view_model, + #[weak] + view_model, async move { view_model.send_thingy().await; } @@ -54,7 +55,8 @@ mod imp { let view_model = view_model.as_ref().unwrap(); let pin = entry.text().to_string(); glib::spawn_future_local(clone!( - #[weak] view_model, + #[weak] + view_model, async move { view_model.send_usb_device_pin(pin).await; } @@ -67,8 +69,9 @@ mod imp { let view_model = view_model.as_ref().unwrap(); let pin = entry.text().to_string(); glib::spawn_future_local(clone!( - #[weak] view_model, - async move { + #[weak] + view_model, + async move { view_model.send_internal_device_pin(pin).await; } )); @@ -158,38 +161,48 @@ impl ExampleApplicationWindow { let view_model = view_model.as_ref().expect("view model to exist"); let stack: >k::Stack = &self.imp().stack.get(); view_model.connect_selected_device_notify(clone!( - #[weak] stack, + #[weak] + stack, move |vm| { let d = vm.selected_device(); - let d = d.and_downcast_ref::().expect("selected device to exist at notify"); + let d = d + .and_downcast_ref::() + .expect("selected device to exist at notify"); match d.transport().try_into() { // TODO: Can multiple resident_keys exist on USB for same origin? // If so, we need to transition this to choose_credential as well. // For now, we'll skip it. Ok(Transport::Usb) => stack.set_visible_child_name("usb"), Ok(Transport::Internal) => stack.set_visible_child_name("choose_credential"), - _ => { }, + _ => {} }; - })); + } + )); view_model.connect_selected_credential_notify(clone!( - #[weak] stack, + #[weak] + stack, move |vm| { let c = vm.selected_credential(); - if c.is_none() || c.unwrap().is_empty() { return; } + if c.is_none() || c.unwrap().is_empty() { + return; + } let d = vm.selected_device(); - let d = d.and_downcast_ref::().expect("selected device to exist at notify"); + let d = d + .and_downcast_ref::() + .expect("selected device to exist at notify"); match d.transport().try_into() { Ok(Transport::Usb) => stack.set_visible_child_name("usb"), Ok(Transport::Internal) => stack.set_visible_child_name("internal"), - _ => { }, + _ => {} }; } )); view_model.connect_completed_notify(clone!( - #[weak] stack, + #[weak] + stack, move |vm| { if vm.completed() { stack.set_visible_child_name("completed"); diff --git a/xyz-iinuwa-credential-manager-portal-gtk/tests/dbus.rs b/xyz-iinuwa-credential-manager-portal-gtk/tests/dbus.rs index 2089b9de..2e7fe811 100644 --- a/xyz-iinuwa-credential-manager-portal-gtk/tests/dbus.rs +++ b/xyz-iinuwa-credential-manager-portal-gtk/tests/dbus.rs @@ -10,7 +10,9 @@ fn test_client_capabilities() { let client = DbusClient::new(); let msg = client.call_method("GetClientCapabilities", &()).unwrap(); let body = msg.body(); - let rsp: HashMap = body.deserialize::>().unwrap() + let rsp: HashMap = body + .deserialize::>() + .unwrap() .into_iter() .map(|(k, v)| (k, v.try_into().unwrap())) .collect(); @@ -55,11 +57,16 @@ mod client { B: Serialize + DynamicType, { let connection = Connection::session().unwrap(); - let message = connection.call_method(Some(SERVICE_NAME), PATH, Some(INTERFACE), method_name, body); + let message = connection.call_method( + Some(SERVICE_NAME), + PATH, + Some(INTERFACE), + method_name, + body, + ); connection.close().unwrap(); message } - } impl Drop for DbusClient { fn drop(&mut self) {