diff --git a/CHANGELOG-npm.md b/CHANGELOG-npm.md index fc79986..ba4be9f 100644 --- a/CHANGELOG-npm.md +++ b/CHANGELOG-npm.md @@ -1,7 +1,8 @@ # Changelog -## [Unreleased] +## 0.10.0 - Add `bip85AppBip39()` +- Add support for BitBox02 Nova ## 0.9.1 - WebHID: Automatically connect to a previoulsy connected device diff --git a/CHANGELOG-rust.md b/CHANGELOG-rust.md index b2ce5e2..5a85bfb 100644 --- a/CHANGELOG-rust.md +++ b/CHANGELOG-rust.md @@ -1,5 +1,8 @@ # Changelog +## 0.9.0 +- Add support for BitBox02 Nova + ## 0.8.0 - Add `bip85_app_bip39()` - Make the `simulator` feature work with the `multithreaded` feature diff --git a/Cargo.lock b/Cargo.lock index 603607b..ad7a2d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -162,7 +162,7 @@ checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" [[package]] name = "bitbox-api" -version = "0.8.0" +version = "0.9.0" dependencies = [ "async-trait", "base32", diff --git a/Cargo.toml b/Cargo.toml index 4d35fea..5efab3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "bitbox-api" authors = ["Marko Bencun "] -version = "0.8.0" +version = "0.9.0" homepage = "https://bitbox.swiss/" repository = "https://github.com/BitBoxSwiss/bitbox-api-rs/" readme = "README-rust.md" edition = "2021" license = "Apache-2.0" -description = "A library to interact with the BitBox02 hardware wallet" +description = "A library to interact with BitBox hardware wallets" keywords = ["bitbox", "api", "bitcoin", "wasm"] categories = ["api-bindings", "cryptography"] diff --git a/ci.sh b/ci.sh index 83bfc2e..1ea144f 100755 --- a/ci.sh +++ b/ci.sh @@ -12,7 +12,7 @@ features=( examples=( "--example singlethreaded --features=usb,tokio/rt,tokio/macros" "--example multithreaded --features=usb,tokio/rt,tokio/macros,tokio/rt-multi-thread,multithreaded" - " --example btc_signtx --features=usb,tokio/rt,tokio/macros" + "--example btc_signtx --features=usb,tokio/rt,tokio/macros" "--example btc_sign_psbt --features=usb,tokio/rt,tokio/macros" "--example btc_sign_msg --features=usb,tokio/rt,tokio/macros" "--example btc_miniscript --features=usb,tokio/rt,tokio/macros" diff --git a/sandbox/package-lock.json b/sandbox/package-lock.json index 4102d41..1934285 100644 --- a/sandbox/package-lock.json +++ b/sandbox/package-lock.json @@ -30,7 +30,7 @@ }, "../pkg": { "name": "bitbox-api", - "version": "0.9.1", + "version": "0.10.0", "license": "Apache-2.0" }, "node_modules/@esbuild/aix-ppc64": { diff --git a/src/cardano.rs b/src/cardano.rs index 148c3bd..38dec31 100644 --- a/src/cardano.rs +++ b/src/cardano.rs @@ -89,7 +89,7 @@ impl PairedBitBox { /// Does this device support Cardano functionality? Currently this means BitBox02 Multi. pub fn cardano_supported(&self) -> bool { - matches!(self.product(), crate::Product::BitBox02Multi) + self.is_multi_edition() } /// Query the device for xpubs. The result contains one xpub per requested keypath. Each xpub is diff --git a/src/communication.rs b/src/communication.rs index 03e6fa9..2e852c6 100644 --- a/src/communication.rs +++ b/src/communication.rs @@ -151,6 +151,8 @@ pub enum Product { Unknown, BitBox02Multi, BitBox02BtcOnly, + BitBox02NovaMulti, + BitBox02NovaBtcOnly, } #[derive(Debug)] @@ -187,6 +189,7 @@ async fn get_info(communication: &dyn ReadWrite) -> Result { let version = semver::Version::parse(version_str).or(Err(Error::Info))?; const PLATFORM_BITBOX02: u8 = 0x00; + const PLATFORM_BITBOX02_NOVA: u8 = 0x02; const BITBOX02_EDITION_MULTI: u8 = 0x00; const BITBOX02_EDITION_BTCONLY: u8 = 0x01; let platform_byte = *response.first().ok_or(Error::Info)?; @@ -198,6 +201,8 @@ async fn get_info(communication: &dyn ReadWrite) -> Result { product: match (platform_byte, edition_byte) { (PLATFORM_BITBOX02, BITBOX02_EDITION_MULTI) => Product::BitBox02Multi, (PLATFORM_BITBOX02, BITBOX02_EDITION_BTCONLY) => Product::BitBox02BtcOnly, + (PLATFORM_BITBOX02_NOVA, BITBOX02_EDITION_MULTI) => Product::BitBox02NovaMulti, + (PLATFORM_BITBOX02_NOVA, BITBOX02_EDITION_BTCONLY) => Product::BitBox02NovaBtcOnly, _ => Product::Unknown, }, unlocked: match unlocked_byte { diff --git a/src/eth.rs b/src/eth.rs index 28a8c9e..c73af1d 100644 --- a/src/eth.rs +++ b/src/eth.rs @@ -38,7 +38,7 @@ impl PairedBitBox { /// Does this device support ETH functionality? Currently this means BitBox02 Multi. pub fn eth_supported(&self) -> bool { - matches!(self.product(), crate::Product::BitBox02Multi) + self.is_multi_edition() } /// Query the device for an xpub. diff --git a/src/lib.rs b/src/lib.rs index 25c093b..5dd33cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -346,6 +346,13 @@ impl PairedBitBox { self.communication.info.product } + fn is_multi_edition(&self) -> bool { + matches!( + self.product(), + crate::Product::BitBox02Multi | crate::Product::BitBox02NovaMulti + ) + } + /// Returns the firmware version. pub fn version(&self) -> &semver::Version { &self.communication.info.version diff --git a/src/u2fframing.rs b/src/u2fframing.rs index a948fef..96529be 100644 --- a/src/u2fframing.rs +++ b/src/u2fframing.rs @@ -83,11 +83,13 @@ pub fn generate_cid() -> u32 { // U2FWS (U2F WebSocket framing protocol) writes u2fhid header and payload as single package (up to // 7+7609 bytes) +#[cfg(feature = "wasm")] pub struct U2fWs { cid: u32, cmd: u8, } +#[cfg(feature = "wasm")] impl U2fWs { pub fn new(cmd: u8) -> Self { U2fWs { @@ -102,12 +104,14 @@ impl U2fWs { } } +#[cfg(feature = "wasm")] impl Default for U2fWs { fn default() -> Self { Self::new(0) } } +#[cfg(feature = "wasm")] impl U2FFraming for U2fWs { fn encode(&self, message: &[u8], mut buf: &mut [u8]) -> io::Result { let len = encode_header_init(self.cid, self.cmd, message.len() as u16, buf)?; @@ -314,6 +318,7 @@ mod tests { assert_eq!(&data[..], &payload[..]); } + #[cfg(feature = "wasm")] #[test] fn test_u2fws_encode_single() { let codec = U2fWs::with_cid(0xEEEEEEEE, 0x55); @@ -326,6 +331,7 @@ mod tests { ); } + #[cfg(feature = "wasm")] #[test] fn test_u2fws_encode_multi() { let payload: Vec = (0..65u8).collect(); @@ -339,6 +345,7 @@ mod tests { assert_eq!(&data[..len], &expect[..]); } + #[cfg(feature = "wasm")] #[test] fn test_u2fws_decode_single() { let codec = U2fWs::with_cid(0xEEEEEEEE, 0x55); @@ -349,6 +356,7 @@ mod tests { assert_eq!(&data[..], b"\x01\x02\x03\x04"); } + #[cfg(feature = "wasm")] #[test] fn test_u2fws_decode_multi() { let payload: Vec = (0..65u8).collect(); diff --git a/src/usb.rs b/src/usb.rs index f26fdc6..fdb279e 100644 --- a/src/usb.rs +++ b/src/usb.rs @@ -7,10 +7,15 @@ use std::sync::Mutex; use super::communication::{Error as CommunicationError, ReadWrite}; -/// The hid product string of the multi edition firmware. -const FIRMWARE_PRODUCT_STRING_MULTI: &str = "BitBox02"; -/// The hid product string of the btc-only edition firmware. -const FIRMWARE_PRODUCT_STRING_BTCONLY: &str = "BitBox02BTC"; +/// The hid product string of the BitBox02 multi edition firmware. +const FIRMWARE_PRODUCT_STRING_BITBOX02_MULTI: &str = "BitBox02"; +/// The hid product string of the BitBox02 btc-only edition firmware. +const FIRMWARE_PRODUCT_STRING_BITBOX02_BTCONLY: &str = "BitBox02BTC"; + +/// The hid product string of the BitBox02 Nova multi edition firmware. +const FIRMWARE_PRODUCT_STRING_BITBOX02_NOVA_MULTI: &str = "BitBox02 Nova Multi"; +/// The hid product string of the BitBox02 Nova btc-only edition firmware. +const FIRMWARE_PRODUCT_STRING_BITBOX02_NOVA_BTCONLY: &str = "BitBox02 Nova BTC-only"; #[cfg(feature = "multithreaded")] pub(crate) struct HidDevice(Mutex); @@ -75,10 +80,12 @@ pub enum UsbError { pub fn is_bitbox02(device_info: &hidapi::DeviceInfo) -> bool { (matches!( device_info.product_string(), - Some(FIRMWARE_PRODUCT_STRING_MULTI) - ) || matches!( - device_info.product_string(), - Some(FIRMWARE_PRODUCT_STRING_BTCONLY) + Some( + FIRMWARE_PRODUCT_STRING_BITBOX02_MULTI + | FIRMWARE_PRODUCT_STRING_BITBOX02_BTCONLY + | FIRMWARE_PRODUCT_STRING_BITBOX02_NOVA_MULTI + | FIRMWARE_PRODUCT_STRING_BITBOX02_NOVA_BTCONLY + ) )) && device_info.vendor_id() == VENDOR_ID && device_info.product_id() == PRODUCT_ID && (device_info.usage_page() == 0xffff || device_info.interface_number() == 0) diff --git a/src/wasm/mod.rs b/src/wasm/mod.rs index 1a3ad1a..e9f2a25 100644 --- a/src/wasm/mod.rs +++ b/src/wasm/mod.rs @@ -211,6 +211,10 @@ impl PairedBitBox { crate::Product::Unknown => JsValue::from_str("unknown").into(), crate::Product::BitBox02Multi => JsValue::from_str("bitbox02-multi").into(), crate::Product::BitBox02BtcOnly => JsValue::from_str("bitbox02-btconly").into(), + crate::Product::BitBox02NovaMulti => JsValue::from_str("bitbox02-nova-multi").into(), + crate::Product::BitBox02NovaBtcOnly => { + JsValue::from_str("bitbox02-nova-btconly").into() + } } } diff --git a/src/wasm/types.rs b/src/wasm/types.rs index 712d1f2..bb35033 100644 --- a/src/wasm/types.rs +++ b/src/wasm/types.rs @@ -11,7 +11,7 @@ extern "C" { #[wasm_bindgen(typescript_custom_section)] const TS_TYPES: &'static str = r#" type OnCloseCb = undefined | (() => void); -type Product = 'unknown' | 'bitbox02-multi' | 'bitbox02-btconly'; +type Product = 'unknown' | 'bitbox02-multi' | 'bitbox02-btconly' | 'bitbox02-nova-multi' | 'bitbox02-nova-btconly'; type BtcCoin = 'btc' | 'tbtc' | 'ltc' | 'tltc' | 'rbtc'; type BtcFormatUnit = 'default' | 'sat'; type XPubType = 'tpub' | 'xpub' | 'ypub' | 'zpub' | 'vpub' | 'upub' | 'Vpub' | 'Zpub' | 'Upub' | 'Ypub';