Skip to content

Commit

Permalink
Prepare for release
Browse files Browse the repository at this point in the history
  • Loading branch information
nickray committed Nov 6, 2021
1 parent e475782 commit 4427112
Show file tree
Hide file tree
Showing 14 changed files with 88 additions and 85 deletions.
8 changes: 8 additions & 0 deletions 70-solo2.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# NXP LPC55 ROM bootloader (unmodified)
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1fc9", ATTRS{idProduct}=="0021", TAG+="uaccess"
# NXP LPC55 ROM bootloader (with Solo 2 VID:PID)
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="beee", TAG+="uaccess"
# Solo 2
SUBSYSTEM=="tty", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="beee", TAG+="uaccess"
# Solo 2
SUBSYSTEM=="usb", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="beee", TAG+="uaccess"
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.0.6] - 2021-11-06

### Changed

- No more async - we're not a high throughput webserver
- Nicer user dialogs (dialoguer/indicatif)
- Model devices modes (bootloader/card)
- Add udev rules

## [0.0.5] - 2021-11-06

### Added
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "solo2"
version = "0.0.5"
version = "0.0.6"
authors = ["SoloKeys Developers"]
edition = "2021"
rust-version = "1.56"
Expand Down
10 changes: 5 additions & 5 deletions src/apps.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use hex_literal::hex;

use crate::device::{prompt_user_to_select_device, Device};
use crate::{Card, Result, Uuid};
use crate::device::{Device, prompt_user_to_select_device};

pub mod admin;
pub mod ndef;
Expand Down Expand Up @@ -53,7 +53,6 @@ pub trait App: Sized {
fn card(&mut self) -> &mut Card;

fn connect(uuid: Option<Uuid>) -> Result<Card> {

let mut cards = Card::list(Default::default());

if cards.is_empty() {
Expand All @@ -73,10 +72,11 @@ pub trait App: Sized {
}
}

return Err(anyhow::anyhow!("Could not find any Solo 2 device with uuid {}.", uuid.hex()));

return Err(anyhow::anyhow!(
"Could not find any Solo 2 device with uuid {}.",
uuid.hex()
));
} else {

let devices = cards.into_iter().map(Device::from).collect();

let selected = prompt_user_to_select_device(devices)?;
Expand Down
5 changes: 1 addition & 4 deletions src/apps/oath.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use core::{
convert::{TryFrom, TryInto},
fmt,
};
use core::fmt;

use anyhow::anyhow;
use flexiber::{Encodable, TaggedSlice};
Expand Down
2 changes: 0 additions & 2 deletions src/apps/provisioner.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use core::convert::TryInto;

use anyhow::anyhow;
use iso7816::Instruction;

Expand Down
7 changes: 3 additions & 4 deletions src/bin/solo2/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ fn main() {
}

fn try_main(args: clap::ArgMatches<'_>) -> anyhow::Result<()> {

let uuid = args.value_of("uuid")
let uuid = args
.value_of("uuid")
// if uuid is Some, parse and fail on invalidity (no silent failure)
.map(|uuid| solo2::Uuid::from_hex(&uuid))
.map(|uuid| solo2::Uuid::from_hex(uuid))
.transpose()?;

if let Some(args) = args.subcommand_matches("app") {
Expand Down Expand Up @@ -229,7 +229,6 @@ fn try_main(args: clap::ArgMatches<'_>) -> anyhow::Result<()> {
}

if let Some(_args) = args.subcommand_matches("list") {

let devices = solo2::Device::list();
for device in devices {
println!("{}", &device);
Expand Down
2 changes: 0 additions & 2 deletions src/dev_pki.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
//! In particular, there is no root CA, no use of hardware keys / PKCS #11,
//! no revocation, etc. etc.

use core::convert::TryInto;

use pkcs8::FromPrivateKey as _;
use rand_core::{OsRng, RngCore};

Expand Down
66 changes: 37 additions & 29 deletions src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@
use anyhow::anyhow;
use lpc55::bootloader::Bootloader;

use core::fmt;
use crate::{Card, Result, Uuid};
use core::fmt;

// #[derive(Debug, Eq, PartialEq)]
pub enum Device {
Bootloader(Bootloader),
Card(Card),
}


impl fmt::Display for Device {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Device::Bootloader(bootloader) =>
f.write_fmt(format_args!("Bootloader UUID: {}", Uuid::from(bootloader.uuid).hex())),
Device::Bootloader(bootloader) => f.write_fmt(format_args!(
"Bootloader UUID: {}",
Uuid::from(bootloader.uuid).hex()
)),
Device::Card(card) => card.fmt(f),
}
}
Expand All @@ -26,18 +27,21 @@ impl fmt::Display for Device {
impl Device {
pub fn list() -> Vec<Self> {
let bootloaders = Bootloader::list().into_iter().map(Device::from);
let cards = Card::list(crate::smartcard::Filter::SoloCards).into_iter().map(Device::from);
let cards = Card::list(crate::smartcard::Filter::SoloCards)
.into_iter()
.map(Device::from);

let devices = bootloaders.chain(cards).collect();
devices
bootloaders.chain(cards).collect()
}

/// If this is a Solo device, this will successfully report the UUID.
/// Not guaranteed to work with other devices.
pub fn uuid(&self) -> Result<Uuid> {
match self {
Device::Bootloader(bootloader) => Ok(bootloader.uuid.into()),
Device::Card(card) => card.uuid.ok_or(anyhow!("Device does not have a UUID")),
Device::Card(card) => card
.uuid
.ok_or_else(|| anyhow!("Device does not have a UUID")),
}
}

Expand Down Expand Up @@ -79,7 +83,10 @@ pub fn find_bootloader(uuid: Option<Uuid>) -> Result<Bootloader> {
return Ok(bootloader);
}
}
return Err(anyhow!("Could not find any Solo 2 device with uuid {}.", uuid.hex()));
return Err(anyhow!(
"Could not find any Solo 2 device with uuid {}.",
uuid.hex()
));
} else {
let mut devices: Vec<Device> = Default::default();
for bootloader in bootloaders {
Expand All @@ -97,35 +104,36 @@ pub fn prompt_user_to_select_device(mut devices: Vec<Device>) -> Result<Device>
return Err(anyhow!("No Solo 2 devices connected"));
}

let items: Vec<String> = devices.iter().map(|device| {
match device {
Device::Bootloader(bootloader) => {
format!(
"Bootloader UUID: {}",
hex::encode(bootloader.uuid.to_be_bytes())
)

},
Device::Card(card) => {
if let Some(uuid) = card.uuid {
// format!("\"{}\" UUID: {}", card.reader_name, hex::encode(uuid.to_be_bytes()))
format!("Solo 2 {}", uuid.hex())
} else {
format!(" \"{}\"", card.reader_name)
let items: Vec<String> = devices
.iter()
.map(|device| {
match device {
Device::Bootloader(bootloader) => {
format!(
"Bootloader UUID: {}",
hex::encode(bootloader.uuid.to_be_bytes())
)
}
Device::Card(card) => {
if let Some(uuid) = card.uuid {
// format!("\"{}\" UUID: {}", card.reader_name, hex::encode(uuid.to_be_bytes()))
format!("Solo 2 {}", uuid.hex())
} else {
format!(" \"{}\"", card.reader_name)
}
}
}
}
}).collect();
})
.collect();

use dialoguer::{Select, theme};
use dialoguer::{theme, Select};
// let selection = Select::with_theme(&theme::SimpleTheme)
let selection = Select::with_theme(&theme::ColorfulTheme::default())
.with_prompt("Multiple Solo 2 devices connected, select one or hit Escape key")
.items(&items)
.default(0)
.interact_opt()?
.ok_or(anyhow!("No device selected"))?;
.ok_or_else(|| anyhow!("No device selected"))?;

Ok(devices.remove(selection))

}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![deny(warnings, trivial_casts, unused_qualifications)]

#[macro_use]
extern crate log;

Expand Down
28 changes: 8 additions & 20 deletions src/smartcard.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::anyhow;
use core::{convert::{TryFrom, TryInto}, fmt};
use core::fmt;
use iso7816::Status;

use pcsc::{Context, Protocols, Scope, ShareMode};
Expand Down Expand Up @@ -44,20 +44,16 @@ impl TryFrom<(&std::ffi::CStr, &Context)> for Card {
Ok(Self {
card,
reader_name: reader.to_str().unwrap().to_owned(),
uuid: uuid_maybe
uuid: uuid_maybe,
})
}
}

impl Card {
pub fn list(filter: Filter) -> Vec<Self> {
let cards = match Self::try_list() {
Ok(cards) => {
cards
}
_ => {
Default::default()
}
Ok(cards) => cards,
_ => Default::default(),
};
match filter {
Filter::AllCards => cards,
Expand All @@ -69,7 +65,6 @@ impl Card {
}

pub fn try_list() -> crate::Result<Vec<Self>> {

let mut cards_with_trussed: Vec<Self> = Default::default();

let context = Context::establish(Scope::User)?;
Expand Down Expand Up @@ -116,18 +111,11 @@ impl Card {
Some(&aid),
)?;

let uuid_bytes = Self::call_card(
card,
0,
apps::admin::App::UUID_COMMAND,
0x00,
0x00,
None,
)?;
let uuid_bytes =
Self::call_card(card, 0, apps::admin::App::UUID_COMMAND, 0x00, 0x00, None)?;

Ok(Uuid::try_from(uuid_bytes.as_ref())
.map_err(|_| anyhow!("Did not read 16 byte uuid from mgmt app."))?
)
Uuid::try_from(uuid_bytes.as_ref())
.map_err(|_| anyhow!("Did not read 16 byte uuid from mgmt app."))
}

fn call_card(
Expand Down
26 changes: 13 additions & 13 deletions src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use anyhow::anyhow;
use lpc55::bootloader::Bootloader;
use serde_json::{from_value, Value};

use crate::{Card, smartcard, Uuid};
use crate::apps::App;
use crate::apps::admin;
use crate::device::{Device, prompt_user_to_select_device};
use crate::apps::App;
use crate::device::{prompt_user_to_select_device, Device};
use crate::{smartcard, Card, Uuid};

pub fn download_latest_solokeys_firmware() -> crate::Result<Vec<u8>> {
println!("Downloading latest release from https://github.com/solokeys/solo2/");
Expand Down Expand Up @@ -48,7 +48,7 @@ pub fn download_latest_solokeys_firmware() -> crate::Result<Vec<u8>> {
.set("User-Agent", "solo2-cli")
.call()?
.into_string()?;
sha256hash = Some(hashfile.split(" ").collect::<Vec<&str>>()[0].into());
sha256hash = Some(hashfile.split(' ').collect::<Vec<&str>>()[0].into());
}
}

Expand All @@ -71,7 +71,7 @@ pub fn download_latest_solokeys_firmware() -> crate::Result<Vec<u8>> {
}

// A rather tolerant update function, intended to be used by end users.
pub fn run_update_procedure (
pub fn run_update_procedure(
sbfile: Option<String>,
uuid: Option<Uuid>,
_skip_major_prompt: bool,
Expand Down Expand Up @@ -99,13 +99,13 @@ pub fn run_update_procedure (
match device.uuid() {
Ok(device_uuid) => {
if device_uuid == uuid {
return program_device(device, sbfile)
return program_device(device, sbfile);
}
}
_ => continue,
}
}
return Err(anyhow!("Cannot find solo2 device with UUID {}", uuid.hex()))
return Err(anyhow!("Cannot find solo2 device with UUID {}", uuid.hex()));
} else if update_all {
for device in devices {
program_device(device, sbfile.clone())?;
Expand All @@ -128,8 +128,8 @@ pub fn program_device(device: Device, sbfile: Vec<u8>) -> crate::Result<()> {
let device_version: u32 = admin.version()?.into();
let sb2_product_version =
lpc55::secure_binary::Sb2Header::from_bytes(&sbfile.as_slice()[..96])
.unwrap()
.product_version();
.unwrap()
.product_version();

// Device stores version as:
// major minor patch
Expand All @@ -139,16 +139,16 @@ pub fn program_device(device: Device, sbfile: Vec<u8>) -> crate::Result<()> {
info!("new sb2 firmware version: {:?}", sb2_product_version);

if device_version_major < sb2_product_version.major as u32 {
use dialoguer::{Confirm, theme};
use dialoguer::{theme, Confirm};
println!("Warning: This is is major update and it could risk breaking any current credentials on your key.");
println!("Check latest release notes here to double check: https://github.com/solokeys/solo2/releases");
println!("If you haven't used your key for anything yet, you can ignore this.");
println!("If you haven't used your key for anything yet, you can ignore this.\n");

println!("");
if Confirm::with_theme(&theme::ColorfulTheme::default())
.with_prompt("Continue?")
.wait_for_newline(true)
.interact()? {
.interact()?
{
println!("Continuing");
} else {
return Err(anyhow!("User aborted."));
Expand Down
Loading

0 comments on commit 4427112

Please sign in to comment.