From 8d73603ad2735884ed96336be44bbbb222d88b41 Mon Sep 17 00:00:00 2001 From: Jaci Brunning Date: Tue, 26 Dec 2023 22:22:26 +1100 Subject: [PATCH] Enable firmware validation --- grapple-hook/grapple-hook-macros/src/lib.rs | 15 +++++-- grapple-hook/package.json | 2 +- grapple-hook/src-tauri/Cargo.lock | 6 +-- grapple-hook/src-tauri/Cargo.toml | 2 +- .../src-tauri/src/devices/device_manager.rs | 4 +- .../src-tauri/src/devices/lasercan.rs | 16 ++++++-- grapple-hook/src-tauri/src/devices/mod.rs | 41 +++++++++++-------- grapple-hook/src-tauri/tauri.conf.json | 2 +- 8 files changed, 57 insertions(+), 31 deletions(-) diff --git a/grapple-hook/grapple-hook-macros/src/lib.rs b/grapple-hook/grapple-hook-macros/src/lib.rs index a28bd0e..38a84ce 100644 --- a/grapple-hook/grapple-hook-macros/src/lib.rs +++ b/grapple-hook/grapple-hook-macros/src/lib.rs @@ -172,6 +172,13 @@ pub fn rpc(_attr: TokenStream, input: TokenStream) -> TokenStream { _ => Err("Not a path!").unwrap(), }; + let boundless_generics = generics.params.iter().map(|x| match x { + syn::GenericParam::Lifetime(lt) => { let l = <.lifetime; quote!{ #l } }, + syn::GenericParam::Type(t) => { let t = &t.ident; quote! { #t } }, + syn::GenericParam::Const(_c) => quote!{}, + }); + let boundless_generics2 = boundless_generics.clone(); + let items = t.items.iter(); let fns = t.items.iter().filter_map(|x| match x { @@ -230,7 +237,7 @@ pub fn rpc(_attr: TokenStream, input: TokenStream) -> TokenStream { }; // TODO: These need to eject the inner type from anyhow::Result. - quote! { + let q = quote! { #[derive(serde::Serialize, serde::Deserialize, schemars::JsonSchema)] #[serde(tag="method", content="data")] pub enum #request_enum_ident { @@ -251,12 +258,14 @@ pub fn rpc(_attr: TokenStream, input: TokenStream) -> TokenStream { } #[async_trait::async_trait] - impl RpcBase for #ty { + impl #generics RpcBase for #ty { async fn rpc_call(&self, data: serde_json::Value) -> anyhow::Result { serde_json::to_value(self.rpc_process(serde_json::from_value(data).map_err(|e| anyhow::anyhow!(e))?).await?).map_err(|e| anyhow::anyhow!(e)) } } - }.into() + }; + + q.into() } /* Helpers */ diff --git a/grapple-hook/package.json b/grapple-hook/package.json index 5c7a65b..4d9ec87 100644 --- a/grapple-hook/package.json +++ b/grapple-hook/package.json @@ -1,7 +1,7 @@ { "name": "grapple-hook", "private": true, - "version": "24.0.0", + "version": "24.0.1", "type": "module", "scripts": { "dev": "vite", diff --git a/grapple-hook/src-tauri/Cargo.lock b/grapple-hook/src-tauri/Cargo.lock index 7003b75..783cba9 100644 --- a/grapple-hook/src-tauri/Cargo.lock +++ b/grapple-hook/src-tauri/Cargo.lock @@ -1158,9 +1158,9 @@ dependencies = [ [[package]] name = "grapple-frc-msgs" -version = "2024.0.5" +version = "2024.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b0255bc7532ea01eb1d10406bf34e998f4f4ec4c4da13985f424b2450f8d05" +checksum = "7873a0302eaf78396f0f8def395b470f6ebe36649e770fa3312d7ad31f073072" dependencies = [ "anyhow", "binmarshal", @@ -1172,7 +1172,7 @@ dependencies = [ [[package]] name = "grapple-hook" -version = "24.0.0" +version = "24.0.1" dependencies = [ "anyhow", "async-trait", diff --git a/grapple-hook/src-tauri/Cargo.toml b/grapple-hook/src-tauri/Cargo.toml index 4c04515..d71db4e 100644 --- a/grapple-hook/src-tauri/Cargo.toml +++ b/grapple-hook/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grapple-hook" -version = "24.0.0" +version = "24.0.1" description = "Configuration Tool for Grapple Hardware" authors = ["Jaci Brunning "] license = "GPLv3" diff --git a/grapple-hook/src-tauri/src/devices/device_manager.rs b/grapple-hook/src-tauri/src/devices/device_manager.rs index f28de41..cf0edb1 100644 --- a/grapple-hook/src-tauri/src/devices/device_manager.rs +++ b/grapple-hook/src-tauri/src/devices/device_manager.rs @@ -77,8 +77,8 @@ impl DeviceManager { let send = super::SendWrapper(self.send.get(domain).unwrap().clone(), self.replies_waiting.get(domain).unwrap().clone()); let device = match (&id, device_type) { - (DeviceId::Dfu(..), _) => Box::new(FirmwareUpgradeDevice::new(send, info_arc.clone())), - (_, DeviceType::Grapple(GrappleModelId::LaserCan)) => LaserCan::maybe_gate(send, info_arc.clone(), LaserCan::new).await, + (DeviceId::Dfu(..), DeviceType::Grapple(GrappleModelId::LaserCan)) => Box::new(FirmwareUpgradeDevice::::new(send, info_arc.clone())), + (DeviceId::Serial(..), DeviceType::Grapple(GrappleModelId::LaserCan)) => LaserCan::maybe_gate(send, info_arc.clone(), LaserCan::new).await, _ => unreachable!() }; diff --git a/grapple-hook/src-tauri/src/devices/lasercan.rs b/grapple-hook/src-tauri/src/devices/lasercan.rs index 5038651..5ecb73b 100644 --- a/grapple-hook/src-tauri/src/devices/lasercan.rs +++ b/grapple-hook/src-tauri/src/devices/lasercan.rs @@ -1,9 +1,9 @@ -use grapple_frc_msgs::{grapple::{Request, errors::{GrappleError, CowStr}, lasercan::{LaserCanStatusFrame, LaserCanMessage, LaserCanRoi}, GrappleDeviceMessage, TaggedGrappleMessage}, DEVICE_ID_BROADCAST, Message, ManufacturerMessage, request_factory}; +use grapple_frc_msgs::{grapple::{Request, errors::{GrappleError, CowStr}, lasercan::{LaserCanStatusFrame, LaserCanMessage, LaserCanRoi}, GrappleDeviceMessage, TaggedGrappleMessage, device_info::GrappleModelId}, DEVICE_ID_BROADCAST, request_factory}; use grapple_hook_macros::rpc; use tokio::sync::RwLock; use crate::rpc::RpcBase; -use super::{SendWrapper, SharedInfo, GrappleDevice, FirmwareUpgradeDevice, Device, FirmwareUpgradeDeviceRequest, GrappleDeviceRequest, GrappleDeviceResponse, FirmwareUpgradeDeviceResponse, VersionGatedDevice, RootDevice}; +use super::{SendWrapper, SharedInfo, GrappleDevice, Device, GrappleDeviceRequest, GrappleDeviceResponse, VersionGatedDevice, RootDevice, start_field_upgrade, FirmwareValidatingDevice}; #[derive(Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)] pub struct LaserCanStatus { @@ -72,11 +72,21 @@ impl Device for LaserCan { } } +impl FirmwareValidatingDevice for LaserCan { + fn validate_firmware(_info: &super::DeviceInfo, buf: &[u8]) -> anyhow::Result<()> { + if &buf[0x150..0x154] == &[0xBEu8, 0xBAu8, 0xFEu8, 0xCAu8] && buf[0x15c] == (GrappleModelId::LaserCan as u8) { + Ok(()) + } else { + anyhow::bail!("Invalid Firmware File. Are you sure this is the correct firmware?") + } + } +} + #[rpc] impl LaserCan { async fn start_field_upgrade(&self) -> anyhow::Result<()> { let serial = self.info.read().await.require_serial()?; - FirmwareUpgradeDevice::start_field_upgrade(&self.sender, serial).await + start_field_upgrade(&self.sender, serial).await } async fn set_range(&self, long: bool) -> anyhow::Result<()> { diff --git a/grapple-hook/src-tauri/src/devices/mod.rs b/grapple-hook/src-tauri/src/devices/mod.rs index a842ad6..9695fbd 100644 --- a/grapple-hook/src-tauri/src/devices/mod.rs +++ b/grapple-hook/src-tauri/src/devices/mod.rs @@ -4,7 +4,7 @@ pub mod provider_manager; pub mod roborio; pub mod lasercan; -use std::{sync::Arc, time::Duration, collections::{LinkedList, HashMap}}; +use std::{sync::Arc, time::Duration, collections::{LinkedList, HashMap}, marker::PhantomData}; use grapple_frc_msgs::{Validate, grapple::{device_info::GrappleModelId, GrappleDeviceMessage, firmware::GrappleFirmwareMessage, TaggedGrappleMessage, GrappleMessageId}, Message, DEVICE_ID_BROADCAST, ManufacturerMessage, binmarshal::{LengthTaggedVec, BinMarshal}, MessageId}; use grapple_hook_macros::rpc; @@ -165,16 +165,17 @@ impl Device for GrappleDevice {} /* FIRMWARE UPGRADE DEVICE */ -pub struct FirmwareUpgradeDevice { +pub struct FirmwareUpgradeDevice { sender: SendWrapper, info: SharedInfo, progress: Arc>>, - ack: Arc + ack: Arc, + _t: PhantomData } -impl FirmwareUpgradeDevice { +impl FirmwareUpgradeDevice { pub fn new(sender: SendWrapper, info: SharedInfo) -> Self { - Self { sender, info, progress: Arc::new(RwLock::new(None)), ack: Arc::new(Notify::new()) } + Self { sender, info, progress: Arc::new(RwLock::new(None)), ack: Arc::new(Notify::new()), _t: PhantomData } } pub async fn field_upgrade_worker(sender: SendWrapper, id: u8, data: &[u8], progress: Arc>>, ack: Arc) -> anyhow::Result<()> { @@ -207,20 +208,22 @@ impl FirmwareUpgradeDevice { Ok(()) } +} - pub async fn start_field_upgrade(sender: &SendWrapper, serial: u32) -> anyhow::Result<()> { - sender.send(TaggedGrappleMessage::new( - DEVICE_ID_BROADCAST, - GrappleDeviceMessage::FirmwareUpdate( - GrappleFirmwareMessage::StartFieldUpgrade { serial } - ) - )).await - } +pub async fn start_field_upgrade(sender: &SendWrapper, serial: u32) -> anyhow::Result<()> { + sender.send(TaggedGrappleMessage::new( + DEVICE_ID_BROADCAST, + GrappleDeviceMessage::FirmwareUpdate( + GrappleFirmwareMessage::StartFieldUpgrade { serial } + ) + )).await } #[rpc] -impl FirmwareUpgradeDevice { +impl FirmwareUpgradeDevice { async fn do_field_upgrade(&self, data: Vec) -> anyhow::Result<()> { + ::validate_firmware(&*self.info.read().await, &data)?; + let sender = self.sender.clone(); let progress = self.progress.clone(); let id = self.info.read().await.require_device_id()?; @@ -238,14 +241,14 @@ impl FirmwareUpgradeDevice { } } -impl RootDevice for FirmwareUpgradeDevice { +impl RootDevice for FirmwareUpgradeDevice { fn device_class(&self) -> &'static str { "GrappleFirmwareUpgrade" } } #[async_trait::async_trait] -impl Device for FirmwareUpgradeDevice { +impl Device for FirmwareUpgradeDevice { async fn handle(&self, msg: TaggedGrappleMessage) -> anyhow::Result<()> { if msg.device_id == DEVICE_ID_BROADCAST || Some(msg.device_id) == self.info.read().await.device_id { match msg.clone().msg { @@ -262,6 +265,10 @@ impl Device for FirmwareUpgradeDevice { } } +pub trait FirmwareValidatingDevice { + fn validate_firmware(info: &DeviceInfo, buf: &[u8]) -> anyhow::Result<()>; +} + #[async_trait::async_trait] pub trait VersionGatedDevice : RootDevice + Sized + Sync + 'static { fn validate_version(version: Option) -> anyhow::Result<()>; @@ -319,7 +326,7 @@ impl RootDevice for OldVersionDevice { impl OldVersionDevice { async fn start_field_upgrade(&self) -> anyhow::Result<()> { let serial = self.grapple_device.info.read().await.require_serial()?; - FirmwareUpgradeDevice::start_field_upgrade(&self.grapple_device.sender, serial).await + start_field_upgrade(&self.grapple_device.sender, serial).await } async fn get_error(&self) -> anyhow::Result { diff --git a/grapple-hook/src-tauri/tauri.conf.json b/grapple-hook/src-tauri/tauri.conf.json index dd916db..c116ad2 100644 --- a/grapple-hook/src-tauri/tauri.conf.json +++ b/grapple-hook/src-tauri/tauri.conf.json @@ -8,7 +8,7 @@ }, "package": { "productName": "GrappleHook", - "version": "24.0.0" + "version": "24.0.1" }, "tauri": { "allowlist": {